Flexible Depth-First Search With MX

November 26, 2008

Graph theory is an essential component of cheminformatics, if you dig deeply enough. MX is a lightweight cheminformatics toolkit written in Java with a major goal of exposing the most important cheminformatics graph manipulations in a flexible, Java-centric way. Previous releases have focused on implementing subgraph monomorphism functionality for use in substructure search. The new MX release, 0.104.0, introduces support for depth-first traversal. This article will give a simple example using this feature.

Downloading MX

MX can be downloaded in source or binary form:

Scripting MX with JRuby

A previous article outlined the simple steps needed to install JRuby on unix-based systems for scripting MX.

Finding All Paths From a Given Atom

A fundamental graph operation in cheminformatics is finding all paths through a molecule from a starting atom. MX makes this easy with the com.metamolecular.mx.path.PathFinder class. Depth-first traversal is used in creating molecular fingerprints. Another use is in creating SMILES strings, although a limited form of depth-first traversal is used in which each atom in a molecule is traversed only once.

We can create a short library to print out all of the paths through a molecule in JRuby:

require 'mx-0.104.0.jar'
import 'com.metamolecular.mx.path.PathFinder'

class PathPrinter
  def initialize
    @finder = PathFinder.new
  end

  def print_paths atom
    paths = @finder.find_all_paths atom

    puts "printing all paths through the molecule"

    paths.each do |path|
      print_path path
    end
  end

  private

  def print_path path
    path.each do |atom|
      print atom.get_index
      print '-' unless path.get(path.length - 1).equals(atom)
    end

    puts
  end
end

Saving the above code in a file called pathprinter.rb, we can test it from interactive JRuby:

$ jirb
irb(main):001:0> require 'pathprinter'                   
=> true
irb(main):002:0> import com.metamolecular.mx.io.Molecules
=> Java::ComMetamolecularMxIo::Molecules
irb(main):003:0> benzene=Molecules.create_benzene        
=> #<Java::ComMetamolecularMxModel::DefaultMolecule:0x43da1b @java_object=com.metamolecular.mx.model.DefaultMolecule@8a2023>
irb(main):004:0> p=PathPrinter.new                       
=> #<PathPrinter:0x19ed7e @finder=#<Java::ComMetamolecularMxPath::PathFinder:0x3727c5 @java_object=com.metamolecular.mx.path.PathFinder@1140709>>
irb(main):005:0> p.print_paths benzene.get_atom(0)       
printing all paths through the molecule
0-5-4-3-2-1
0-1-2-3-4-5
=> nil

How It Works

Two classes collaborate in this traversal: com.metamolecular.mx.path.PathFinder and com.metamolecular.mx.path.DefaultStep.

Creating a depth-first traversal of your own is as simple as creating a DefaultStep from an Atom and implementing a walk method similar to the one shown below:

public void walk(Step step)
{
  if (!step.hasNextBranch())
  {
    // do something with the completed branch
    
    return;
  }
    
  while(step.hasNextBranch())
  {
    Atom next = step.nextBranch();
    
    if (step.isBranchFeasible(next))
    {
      walk(step.nextStep(next));
      
      step.backTrack();
    }
  }
}

Conclusions

Depth-first traversal is an important tool in any cheminformatics library. MX offers an implementation of this traversal strategy that can be easily customized.