<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -36,16 +36,16 @@ public class DefaultAtomMatcher implements AtomMatcher
   private String symbol;
   private int maximumNeighbors;
   private int minimumNeighbors;
-  private int minimumValence;
-  private int maximumValence;
+  private int minimumUnsaturation;
+  private int maximumUnsaturation;
 
   public DefaultAtomMatcher()
   {
     symbol = null;
     maximumNeighbors = -1;
     minimumNeighbors = -1;
-    minimumValence = -1;
-    maximumValence = -1;
+    minimumUnsaturation = -1;
+    maximumUnsaturation = -1;
   }
 
   public DefaultAtomMatcher(Atom atom)
@@ -54,7 +54,12 @@ public class DefaultAtomMatcher implements AtomMatcher
 
     this.symbol = atom.getSymbol();
     this.minimumNeighbors = atom.countNeighbors();
-    this.minimumValence = atom.countNeighbors() + atom.countVirtualHydrogens();
+    this.minimumUnsaturation = getUnsaturation(atom);
+    
+    if (minimumUnsaturation == 0)
+    {
+      this.maximumUnsaturation = 0;
+    }
   }
 
   public boolean matches(Atom atom)
@@ -74,12 +79,12 @@ public class DefaultAtomMatcher implements AtomMatcher
       return false;
     }
     
-    if (!matchMinimumValence(atom))
+    if (!matchMinimumUnsaturation(atom))
     {
       return false;
     }
     
-    if (!matchMaximumValence(atom))
+    if (!matchMaximumUnsaturation(atom))
     {
       return false;
     }
@@ -87,22 +92,22 @@ public class DefaultAtomMatcher implements AtomMatcher
     return true;
   }
   
-  public void setMinimumValence(int minimum)
+  public void setMinimumUnsaturation(int minimum)
   {
-    if (minimum &gt; maximumValence &amp;&amp; maximumValence != -1)
+    if (minimum &gt; maximumUnsaturation &amp;&amp; maximumUnsaturation != -1)
     {
       throw new IllegalStateException(&quot;Minimum &quot; + minimum + &quot; exceeds maximum&quot;);
     }
-    this.minimumValence = minimum;
+    this.minimumUnsaturation = minimum;
   }
   
-  public void setMaximumValence(int maximum)
+  public void setMaximumUnsaturation(int maximum)
   {
-    if (maximum &lt; minimumValence)
+    if (maximum &lt; minimumUnsaturation)
     {
       throw new IllegalStateException(&quot;Maximum &quot; + maximum + &quot; less than minimum&quot;);
     }
-    this.maximumValence = maximum;
+    this.maximumUnsaturation = maximum;
   }
 
   public void setMaximumNeighbors(int maximum)
@@ -129,6 +134,11 @@ public class DefaultAtomMatcher implements AtomMatcher
   {
     this.symbol = symbol;
   }
+  
+  private int getUnsaturation(Atom atom)
+  {
+    return atom.getValence() - atom.countNeighbors();
+  }
 
   private boolean matchSymbol(Atom atom)
   {
@@ -160,23 +170,23 @@ public class DefaultAtomMatcher implements AtomMatcher
     return atom.countNeighbors() &gt;= minimumNeighbors;
   }
   
-  private boolean matchMinimumValence(Atom atom)
+  private boolean matchMinimumUnsaturation(Atom atom)
   {
-    if (minimumValence == -1)
+    if (minimumUnsaturation == -1)
     {
       return true;
     }
     
-    return atom.countNeighbors() + atom.countVirtualHydrogens() &gt;= minimumValence;
+    return getUnsaturation(atom) &gt;= this.minimumUnsaturation;
   }
   
-  private boolean matchMaximumValence(Atom atom)
+  private boolean matchMaximumUnsaturation(Atom atom)
   {
-    if (maximumValence == -1)
+    if (maximumUnsaturation == -1)
     {
       return true;
     }
     
-    return atom.countNeighbors() + atom.countVirtualHydrogens() &lt;= maximumValence;
+    return getUnsaturation(atom) &lt;= this.maximumUnsaturation;
   }
 }</diff>
      <filename>src/com/metamolecular/mx/query/DefaultAtomMatcher.java</filename>
    </modified>
    <modified>
      <diff>@@ -26,6 +26,7 @@
 package com.metamolecular.mx.test;
 
 import com.metamolecular.mx.io.Molecules;
+import com.metamolecular.mx.model.DefaultMolecule;
 import com.metamolecular.mx.model.Molecule;
 import com.metamolecular.mx.query.DefaultAtomMatcher;
 import junit.framework.TestCase;
@@ -91,40 +92,40 @@ public class DefaultAtomMatcherTest extends TestCase
     assertFalse(matcher.matches(phenol.getAtom(6)));
   }
   
-  public void testItShouldMatchBasedOnMinimumValence()
+  public void testItShouldMatchBasedOnMinimumUnsaturation()
   {
-    matcher.setMinimumValence(3);
+    matcher.setMinimumUnsaturation(1);
     
     assertTrue(matcher.matches(phenol.getAtom(0)));
   }
   
-  public void testItShouldNotMatchBasedOnMinimumValence()
+  public void testItShouldNotMatchBasedOnMinimumUnsaturation()
   {
-    matcher.setMinimumValence(4);
+    matcher.setMinimumUnsaturation(4);
     
     assertFalse(matcher.matches(phenol.getAtom(0)));
   }
   
-  public void testItShouldMatchBasedOnMaximumValence()
+  public void testItShouldMatchBasedOnMaximumUnsaturation()
   {
-    matcher.setMaximumValence(3);
+    matcher.setMaximumUnsaturation(3);
     
     assertTrue(matcher.matches(phenol.getAtom(0)));
   }
   
-  public void testItShouldNotMatchBasedOnMaximumValence()
+  public void testItShouldNotMatchBasedOnMaximumUnsaturation()
   {
-    matcher.setMaximumValence(2);
+    matcher.setMaximumUnsaturation(0);
     
     assertFalse(matcher.matches(phenol.getAtom(0)));
   }
   
-  public void testItThrowsWhenMaximumValenceLessThanMinimumaValence()
+  public void testItThrowsWhenMaximumUnsaturationLessThanMinimumaUnsaturation()
   {
-    matcher.setMinimumValence(3);
+    matcher.setMinimumUnsaturation(3);
     try
     {
-      matcher.setMaximumValence(2);
+      matcher.setMaximumUnsaturation(2);
       fail();
     }
     
@@ -134,13 +135,13 @@ public class DefaultAtomMatcherTest extends TestCase
     }
   }
   
-  public void testItThrowsWhenMinimumValenceGreaterThanMaximumValence()
+  public void testItThrowsWhenMinimumUnsaturationGreaterThanMaximumUnsaturation()
   {
-    matcher.setMaximumValence(3);
+    matcher.setMaximumUnsaturation(3);
     
     try
     {
-      matcher.setMinimumValence(4);
+      matcher.setMinimumUnsaturation(4);
       fail();
     }
     
@@ -200,4 +201,99 @@ public class DefaultAtomMatcherTest extends TestCase
     
     assertFalse(matcher.matches(phenol.getAtom(2)));
   }
+  
+  public void testItDoesntMatchTolueneQuatToNeopentaneQuat()
+  {
+    Molecule toluene = Molecules.createToluene();
+    Molecule neopentane = Molecules.createNeopentane();
+    matcher = new DefaultAtomMatcher(toluene.getAtom(0));
+ 
+    assertFalse(matcher.matches(neopentane.getAtom(0)));
+  }
+  
+  public void testItMatchesEthyleneCarbonToAlleneQuatCarbon()
+  {
+    Molecule ethylene = createEthylene();
+    Molecule allene = createAllene();
+    matcher = new DefaultAtomMatcher(ethylene.getAtom(0));
+    
+    assertTrue(matcher.matches(allene.getAtom(1)));
+  }
+  
+  public void testItDoesntMatchAlleneQuatCarbonToEthyleneCarbon()
+  {
+    Molecule ethylene = createEthylene();
+    Molecule allene = createAllene();
+    matcher = new DefaultAtomMatcher(allene.getAtom(1));
+    
+    assertFalse(matcher.matches(ethylene.getAtom(0)));
+  }
+  
+  public void testItMatchesEthyleneCarbonToAcetyleneCarbon()
+  {
+    Molecule ethylene = createEthylene();
+    Molecule acetylene = createAcetylene();
+    matcher = new DefaultAtomMatcher(ethylene.getAtom(0));
+    
+    assertTrue(matcher.matches(acetylene.getAtom(0)));
+  }
+  
+  public void testItDoesntMatchAcetyleneCarbonToEthyleneCarbon()
+  {
+    Molecule ethylene = createEthylene();
+    Molecule acetylene = createAcetylene();
+    matcher = new DefaultAtomMatcher(acetylene.getAtom(0));
+    
+    assertFalse(matcher.matches(ethylene.getAtom(0)));
+  }
+  
+  public void testItDoesntMatchAcetoneOxygenToIsopropanolOxygen()
+  {
+    Molecule acetone = Molecules.createAcetone();
+    Molecule ipa = createIsopropanol();
+    matcher = new DefaultAtomMatcher(acetone.getAtom(3));
+    
+    assertFalse(matcher.matches(ipa.getAtom(3)));
+  }
+  
+  public void testItDoesntMatchIsopropanolOxygenToAcetoneOxygen()
+  {
+    Molecule acetone = Molecules.createAcetone();
+    Molecule ipa = createIsopropanol();
+    matcher = new DefaultAtomMatcher(ipa.getAtom(3));
+    
+    assertFalse(matcher.matches(acetone.getAtom(3)));
+  }
+  
+  private Molecule createEthylene()
+  {
+    Molecule result = new DefaultMolecule();
+    result.connect(result.addAtom(&quot;C&quot;), result.addAtom(&quot;C&quot;), 2);
+    
+    return result;
+  }
+  
+  private Molecule createAcetylene()
+  {
+    Molecule result = createEthylene();
+    result.getBond(0).setType(3);
+    
+    return result;
+  }
+  
+  private Molecule createAllene()
+  {
+    Molecule result = createEthylene();
+    result.connect(result.getAtom(1), result.addAtom(&quot;C&quot;), 2);
+    
+    return result;
+  }
+  
+  private Molecule createIsopropanol()
+  {
+    Molecule result = Molecules.createAcetone();
+    result.getBond(2).setType(1);
+    
+    return result;
+  }
 }</diff>
      <filename>src/com/metamolecular/mx/test/DefaultAtomMatcherTest.java</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>00b9b4e8ee0627a8a4a965cebe510ecb50a5d6cd</id>
    </parent>
  </parents>
  <author>
    <name>Richard Apodaca</name>
    <email>rapodaca@metamolecular.com</email>
  </author>
  <url>http://github.com/rapodaca/mx/commit/0ab38bada2921c024a2abd159f8bf7be74796007</url>
  <id>0ab38bada2921c024a2abd159f8bf7be74796007</id>
  <committed-date>2009-06-16T12:18:12-07:00</committed-date>
  <authored-date>2009-06-16T12:13:01-07:00</authored-date>
  <message>changed matching concept from valence to unsaturation. Closes #6.</message>
  <tree>e087addf71ec61f821eb11764fbca770f05bac73</tree>
  <committer>
    <name>Richard Apodaca</name>
    <email>rapodaca@metamolecular.com</email>
  </committer>
</commit>
