Exhaustive Ring Perception With MX
The latest release of MX now supports exhaustive ring perception. Both a platform-independent jarfile and source distribution can be downloaded.
Background
The ability to perceive all rings in a chemical structure is essential for a number of important cheminformatics capabilities including Structure Diagram Generation, aromaticity detection, and binary fingerprint generation.
A recent Depth-First article described a ring-perception algorithm that efficiently returns the set of all rings for any molecule. The algorithm, developed by Hanser and coworkers has now been implemented in MX.
MX is a platform-independent, cross-language cheminformatics toolkit written in Java and made available to the cheminformatics community by Metamolecular, LLC.
Examples
Ring perception can be tested conveniently using either JRuby or Jython. In these examples, we'll use JRuby.
To find all rings in benzene, we'd use something like:
jirb
irb(main):001:0> require 'mx-0.108.1.jar'
=> true
irb(main):002:0> import com.metamolecular.mx.ring.HanserRingFinder
=> Java::ComMetamolecularMxRing::HanserRingFinder
irb(main):003:0> import com.metamolecular.mx.io.Molecules
=> Java::ComMetamolecularMxIo::Molecules
irb(main):004:0> benzene = Molecules.create_benzene
=> #<Java::ComMetamolecularMxModel::DefaultMolecule:0x1971eb3 @java_object=com.metamolecular.mx.model.DefaultMolecule@126ba64>
irb(main):005:0> finder = HanserRingFinder.new
=> #<Java::ComMetamolecularMxRing::HanserRingFinder:0x76f2e8 @java_object=com.metamolecular.mx.ring.HanserRingFinder@1458dcb>
irb(main):006:0> rings = finder.find_rings benzene
=> #<Java::JavaUtil::ArrayList:0x1b83048 @java_object=[[com.metamolecular.mx.model.DefaultMolecule$AtomImpl@169dd64, com.metamolecular.mx.model.DefaultMolecule$AtomImpl@145f5e3, com.metamolecular.mx.model.DefaultMolecule$AtomImpl@122d9c, com.metamolecular.mx.model.DefaultMolecule$AtomImpl@170984c, com.metamolecular.mx.model.DefaultMolecule$AtomImpl@11ed166, com.metamolecular.mx.model.DefaultMolecule$AtomImpl@45aa2c, com.metamolecular.mx.model.DefaultMolecule$AtomImpl@169dd64]]>
irb(main):007:0> rings[0].collect{|atom| atom.get_index}.join("-")
=> "5-0-1-2-3-4-5"
irb(main):008:0> rings.size
=> 1
Here, we're taking advantage of the Ruby Array.join
function to place a dash between each atom index.
To really push the system, we could find all rings in cubane:
jirb
irb(main):001:0> require 'mx-0.108.1.jar'
=> true
irb(main):002:0> import com.metamolecular.mx.ring.HanserRingFinder
=> Java::ComMetamolecularMxRing::HanserRingFinder
irb(main):003:0> import com.metamolecular.mx.io.Molecules
=> Java::ComMetamolecularMxIo::Molecules
irb(main):004:0> cubane = Molecules.create_cubane
=> #<Java::ComMetamolecularMxModel::DefaultMolecule:0xe391c4 @java_object=com.metamolecular.mx.model.DefaultMolecule@182a033>
irb(main):005:0> finder = HanserRingFinder.new
=> #<Java::ComMetamolecularMxRing::HanserRingFinder:0x1458dcb @java_object=com.metamolecular.mx.ring.HanserRingFinder@1603522>
irb(main):006:0> rings = finder.find_rings cubane
=> #collection with many objects
irb(main):007:0> rings.size
=> 28
irb(main):008:0> rings[0].collect{|atom| atom.get_index}.join("-")
=> "3-0-1-2-3"
Other Improvements
The MX-0.108.1 release includes some other changes as well.
- Fixes a bug in which multiline SD file data was not read.
- Adds a resources directory containing atomic_system.xml so that the source distribution can compile and all tests will pass.
Conclusions
This first implementation of the Hanser algorithm focuses on correctness, readability, and test coverage over performance. Future releases will address performance in the context of a open, multi-toolkit cheminformatics benchmark suite.