Index: kernel/include/IMP.h
===================================================================
--- kernel/include/IMP.h	(revision 338)
+++ kernel/include/IMP.h	(working copy)
@@ -50,8 +50,11 @@
 #include "IMP/restraints/PairConnectivityRestraint.h"
 #include "IMP/restraints/ExclusionVolumeRestraint.h"
 #include "IMP/restraints/NonbondedRestraint.h"
+#include "IMP/restraints/BondDecoratorRestraint.h"
 #include "IMP/score_states/NonbondedListScoreState.h"
+#include "IMP/score_states/BipartiteNonbondedListScoreState.h"
 #include "IMP/score_states/BondedListScoreState.h"
+#include "IMP/score_states/bonded_lists/BondDecoratorListScoreState.h"
 
 /**
    \namespace IMP The IMP namespace.
Index: kernel/include/IMP/decorators/bond_decorators.h
===================================================================
--- kernel/include/IMP/decorators/bond_decorators.h	(revision 338)
+++ kernel/include/IMP/decorators/bond_decorators.h	(working copy)
@@ -30,6 +30,8 @@
 extern IMPDLLEXPORT  bool bond_keys_initialized_;
 extern IMPDLLEXPORT  IntKey bond_type_key_;
 extern IMPDLLEXPORT  IntKey bond_order_key_;
+extern IMPDLLEXPORT  FloatKey bond_length_key_;
+extern IMPDLLEXPORT  FloatKey bond_stiffness_key_;
 
 } // namespace internal
 
@@ -48,7 +50,8 @@
 public:
   //! The types a bond can have right now
   enum Type {UNKNOWN=-1,
-             COVALENT, HYDROGEN, DISULPHIDE, SALT, PEPTIDE
+             COVALENT, HYDROGEN, DISULPHIDE, SALT, PEPTIDE,
+             CUSTOM
             };
 
   //! Get the atom i of the bond
@@ -61,6 +64,11 @@
                             UNKNOWN);
 
   IMP_DECORATOR_GET_SET_OPT(order, internal::bond_order_key_, Int, Int, 1);
+
+  IMP_DECORATOR_GET_SET_OPT(length, internal::bond_length_key_, Float, 
+                            Float, -1);
+  IMP_DECORATOR_GET_SET_OPT(stiffness, internal::bond_stiffness_key_, Float, 
+                            Float, -1);
 };
 
 IMP_OUTPUT_OPERATOR(BondDecorator);
@@ -81,7 +89,7 @@
   }
 
 
-  //! Get a BondDecorator of the ith child
+  //! Get a BondDecorator of the ith bond
   /** \return decorator of the ith child, or throw and exception if there
               is no such bond
   */
@@ -90,12 +98,30 @@
                                      internal::bond_graph_data_);
     return BondDecorator::cast(p);
   }
+
+  //! Get a BondedDecorator of the ith bonded particle
+  /** \return decorator of the ith child, or throw and exception if there
+              is no such bond
+
+      \note I don't entirely like having this here as it duplicates
+      functionality available otherwise, however it is such a fundamental
+      operation and kind of a pain to write. It also means that we 
+      could later pull the edge endpoints into the vertex if 
+      desired.
+  */
+  BondedDecorator get_bonded(unsigned int i) const {
+    Particle *p= graph_get_edge(get_particle(), i,
+                                     internal::bond_graph_data_);
+    BondDecorator bd= BondDecorator::cast(p);
+    if (bd.get_bonded(0) == *this) return bd.get_bonded(1);
+    else return bd.get_bonded(0);
+  }
 };
 
 IMP_OUTPUT_OPERATOR(BondedDecorator);
 
 
-BondedDecorator BondDecorator::get_bonded(unsigned int i) const
+inline BondedDecorator BondDecorator::get_bonded(unsigned int i) const
 {
   Particle *p= graph_get_node(get_particle(), i,
                                    internal::bond_graph_data_);
@@ -111,6 +137,25 @@
 IMPDLLEXPORT
 BondDecorator bond(BondedDecorator a, BondedDecorator b, Int t);
 
+
+//! Connect the two wrapped particles by a custom bond.
+/** \param[in] a The first Particle as a BondedDecorator
+    \param[in] b The second Particle as a BondedDecorator
+    \param[in] length The length of the bond.
+    \param[in] stiffness The stiffness of the bond.
+    \return BondDecorator of the bond Particle.
+ */
+IMPDLLEXPORT
+inline BondDecorator custom_bond(BondedDecorator a, BondedDecorator b, 
+                          Float length, Float stiffness=-1) {
+  IMP_assert(length>=0, "Length must be positive");
+  BondDecorator bd=bond(a,b, BondDecorator::CUSTOM);
+  bd.set_length(length);
+  if (stiffness >=0) bd.set_stiffness(stiffness);
+  return bd;
+}
+
+
 //! Destroy the bond connecting to particles.
 /** \param[in] b The bond.
  */
Index: kernel/include/IMP/restraints/SConscript
===================================================================
--- kernel/include/IMP/restraints/SConscript	(revision 338)
+++ kernel/include/IMP/restraints/SConscript	(working copy)
@@ -5,7 +5,7 @@
          'SphericalRestraint.h', 'DistanceRestraint.h', 'AngleRestraint.h',
          'DihedralRestraint.h', 'RestraintSet.h', 'ExclusionVolumeRestraint.h',
          'TorusRestraint.h', 'PairConnectivityRestraint.h',
-         'NonbondedRestraint.h']
+         'NonbondedRestraint.h', 'BondDecoratorRestraint.h']
 
 # Install the include files:
 includedir = os.path.join(env['includedir'], 'IMP', 'restraints')
Index: kernel/include/IMP/score_states/SConscript
===================================================================
--- kernel/include/IMP/score_states/SConscript	(revision 338)
+++ kernel/include/IMP/score_states/SConscript	(working copy)
@@ -1,9 +1,12 @@
 import os.path
 Import('env')
 
-files = ['BondedListScoreState.h', 'NonbondedListScoreState.h']
+files = ['BondedListScoreState.h', 'NonbondedListScoreState.h',
+         'BipartiteNonbondedListScoreState.h']
 
 # Install the include files:
 includedir = os.path.join(env['includedir'], 'IMP', 'score_states')
 inst = env.Install(includedir, files)
 env.Alias('install', inst)
+
+SConscript('bonded_lists/SConscript')
Index: kernel/include/IMP/score_states/bonded_lists/BondDecoratorListScoreState.h
===================================================================
--- kernel/include/IMP/score_states/bonded_lists/BondDecoratorListScoreState.h	(revision 0)
+++ kernel/include/IMP/score_states/bonded_lists/BondDecoratorListScoreState.h	(revision 0)
@@ -0,0 +1,57 @@
+/**
+ *  \file BondedListScoreState.h    
+ *  \brief Allow iteration through pairs of a set of atoms.
+ *
+ *  Copyright 2007-8 Sali Lab. All rights reserved.
+ */
+
+#ifndef __IMP_BONDEDDECORLISTSCORESTATE_H
+#define __IMP_BONDEDDECORLISTSCORESTATE_H
+
+#include "../BondedListScoreState.h"
+#include "../../decorators/bond_decorators.h"
+#include <vector>
+
+namespace IMP
+{
+  class BondDecoratorListScoreState;
+  typedef Index<BondDecoratorListScoreState> BondDecoratorListIndex;
+
+  //! Keep track of particles that are connected by BondDecorator bonds.
+  /**
+     We also may want to add lazy rescanning of bonds rather than doing
+     it every update call and a faster lookup of bonds.
+   */
+  class IMPDLLEXPORT BondDecoratorListScoreState: public BondedListScoreState {
+    std::vector<BondDecorator> bonds_;
+    Particles ps_;
+  public:
+    //! Find bonds amongst the following points. 
+    /**
+       \param [in] ps The set of particles to use.
+     */
+    BondDecoratorListScoreState(const Particles &ps);
+    virtual ~BondDecoratorListScoreState(){}
+    //IMP_SCORE_STATE("0.5", "Daniel Russel");
+
+    virtual void set_particles(const Particles &ps);
+
+    virtual bool are_bonded(Particle *a, Particle *b) const;
+
+    virtual void update();
+
+    //! This iterates through the pairs of bonded particles
+    /**
+       \precondition update() must be called first for this to be valid.
+     */
+    typedef std::vector<BondDecorator>::const_iterator BondIterator;
+    BondIterator bonds_begin() const {
+      return bonds_.begin();
+    }
+    BondIterator bonds_end() const {
+      return bonds_.end();
+    }
+  };
+
+}
+#endif
Index: kernel/include/IMP/score_states/bonded_lists/SConscript
===================================================================
--- kernel/include/IMP/score_states/bonded_lists/SConscript	(revision 0)
+++ kernel/include/IMP/score_states/bonded_lists/SConscript	(revision 0)
@@ -0,0 +1,9 @@
+import os.path
+Import('env')
+
+files = ['BondDecoratorListScoreState.h']
+
+# Install the include files:
+includedir = os.path.join(env['includedir'], 'IMP', 'score_states', 'bonded_lists')
+inst = env.Install(includedir, files)
+env.Alias('install', inst)
Index: kernel/pyext/IMP.i
===================================================================
--- kernel/pyext/IMP.i	(revision 338)
+++ kernel/pyext/IMP.i	(working copy)
@@ -28,6 +28,9 @@
   %pythonprepend RestraintSet::add_restraint %{
         args[1].thisown=0
   %}
+  %pythonprepend NonbondedListScoreState::add_bonded_list %{
+        args[1].thisown=0
+  %}
   %pythonprepend DistanceRestraint::DistanceRestraint %{
         args[2].thisown=0
   %}
@@ -46,6 +49,9 @@
   %pythonprepend NonbondedRestraint::NonbondedRestraint %{
         args[1].thisown=0
   %}
+  %pythonprepend BondDecoratorRestraint::BondDecoratorRestraint %{
+        args[1].thisown=0
+  %}
   %pythonprepend DistancePairScore::DistancePairScore %{
         args[1].thisown=0
   %}
@@ -108,10 +114,14 @@
 %include "IMP/restraints/PairConnectivityRestraint.h"
 %include "IMP/restraints/ExclusionVolumeRestraint.h"
 %include "IMP/restraints/NonbondedRestraint.h"
+%include "IMP/restraints/BondDecoratorRestraint.h"
 %include "IMP/score_states/BondedListScoreState.h"
 %include "IMP/score_states/NonbondedListScoreState.h"
+%include "IMP/score_states/BipartiteNonbondedListScoreState.h"
+%include "IMP/score_states/bonded_lists/BondDecoratorListScoreState.h"
 %include "IMP/RigidBody.h"
 
+
 namespace IMP {
   %template(IntIndex) Index<Int>;
   %template(FloatIndex) Index<Float>;
@@ -120,6 +130,7 @@
   %template(RestraintIndex) Index<RestraintTag>;
   %template(ScoreStateIndex) Index<ScoreStateTag>;
   %template(OptimizerStateIndex) Index<OptimizerStateTag>;
+  %template(BondeListIndex) Index<BondedListScoreState>;
   %template(FloatKey) Key<Float>;
   %template(IntKey) Key<Int>;
   %template(StringKey) Key<String>;
Index: kernel/src/SConscript
===================================================================
--- kernel/src/SConscript	(revision 338)
+++ kernel/src/SConscript	(working copy)
@@ -9,6 +9,7 @@
 optimizers_files = SConscript('optimizers/SConscript')
 decorators_files = SConscript('decorators/SConscript')
 unary_functions_files = SConscript('unary_functions/SConscript')
+score_states_files = SConscript('score_states/SConscript')
 pair_scores_files = SConscript('pair_scores/SConscript')
 score_states_files = SConscript('score_states/SConscript')
 
Index: kernel/src/decorators/bond_decorators.cpp
===================================================================
--- kernel/src/decorators/bond_decorators.cpp	(revision 338)
+++ kernel/src/decorators/bond_decorators.cpp	(working copy)
@@ -19,6 +19,7 @@
 FloatKey bond_length_key_;
 IntKey bond_type_key_;
 IntKey bond_order_key_;
+FloatKey bond_stiffness_key_;
 
 } // namespace internal
 
@@ -54,6 +55,8 @@
     internal::bond_graph_data_= internal::GraphData("bond");
     internal::bond_type_key_= IntKey("bond type");
     internal::bond_order_key_=IntKey("bond order");
+    internal::bond_length_key_=FloatKey("bond length");
+    internal::bond_stiffness_key_=FloatKey("bond stiffness");
     internal::bond_keys_initialized_=true;
   }
 }
Index: kernel/src/restraints/SConscript
===================================================================
--- kernel/src/restraints/SConscript	(revision 338)
+++ kernel/src/restraints/SConscript	(working copy)
@@ -5,7 +5,7 @@
          'SphericalRestraint.cpp', 'RestraintSet.cpp',
          'DistanceRestraint.cpp', 'AngleRestraint.cpp', 'DihedralRestraint.cpp',
          'TorusRestraint.cpp', 'ExclusionVolumeRestraint.cpp',
-         'NonbondedRestraint.cpp']
+         'NonbondedRestraint.cpp', 'BondDecoratorRestraint.cpp']
 
 files = [File(x) for x in files]
 Return('files')
Index: kernel/src/score_states/SConscript
===================================================================
--- kernel/src/score_states/SConscript	(revision 338)
+++ kernel/src/score_states/SConscript	(working copy)
@@ -1,6 +1,9 @@
 Import('env')
 
-files = ['NonbondedListScoreState.cpp']
+bd_files= SConscript('bonded_lists/SConscript')
 
+files = ['NonbondedListScoreState.cpp',
+         'BipartiteNonbondedListScoreState.cpp'] +bd_files
+
 files = [File(x) for x in files]
 Return('files')
Index: kernel/test/states/test_nonbonded_list.py
===================================================================
--- kernel/test/states/test_nonbonded_list.py	(revision 338)
+++ kernel/test/states/test_nonbonded_list.py	(working copy)
@@ -13,10 +13,17 @@
     def show(self, t):
         print "One Pair"
 
+class OneScore(IMP.UnaryFunction):
+    def __init__(self):
+        IMP.UnaryFunction.__init__(self)
+    def __call__(self, *args):
+        return 100
+    def show(self, *args):
+        print "One score"
 
 class TestNBL(IMP.test.TestCase):
     def setUp(self):
-        IMP.set_log_level(IMP.TERSE)
+        IMP.set_log_level(IMP.VERBOSE)
 
     def test_it(self):
         """Test the nonbonded list and restraint which uses it"""
@@ -28,14 +35,66 @@
             d.set_x(0)
             d.set_y(1)
             d.set_z(1)
-        s= IMP.NonbondedListScoreState(m.get_particles(), 100)
+        s= IMP.NonbondedListScoreState(m.get_particles())
         m.add_score_state(s)
         o= OnePair()
         r= IMP.NonbondedRestraint(s, o)
         m.add_restraint(r)
         score= m.evaluate(False)
         self.assertEqual(score, 45, "Wrong score")
+    def test_bl(self):
+        """Test the bonded list"""
+        m= IMP.Model()
+        bds=[]
+        for i in range(0,10):
+            p= IMP.Particle()
+            m.add_particle(p)
+            d=IMP.XYZDecorator.create(p)
+            d.set_x(0)
+            d.set_y(1)
+            d.set_z(1)
+            bds.append(IMP.BondedDecorator.create(p))
+        pts=IMP.Particles()
+        for p in m.get_particles():
+            pts.append(p)
+        for i in range(1,10):
+            IMP.custom_bond(bds[i-1], bds[i], 1, .1)
+        s= IMP.NonbondedListScoreState(pts)
+        b= IMP.BondDecoratorListScoreState(pts)
+        s.add_bonded_list(b)
+        m.add_score_state(s)
+        o= OnePair()
+        r= IMP.NonbondedRestraint(s, o)
+        os=OneScore()
+        print os(6)
+        br= IMP.BondDecoratorRestraint(b, os)
+        m.add_restraint(r)
+        m.add_restraint(br)
+        score= m.evaluate( False )
+        self.assertEqual(score, 900+45-9, "Wrong score")
+    def test_bnbl(self):
+        """Test the bipartite nonbonded list and restraint which uses it"""
+        m= IMP.Model()
+        ps0=IMP.Particles()
+        ps1=IMP.Particles()
+        for i in range(0,10):
+            p= IMP.Particle()
+            m.add_particle(p)
+            d=IMP.XYZDecorator.create(p)
+            d.set_x(0)
+            d.set_y(1)
+            d.set_z(1)
+            if (i < 5):
+                ps0.append(p)
+            else:
+                ps1.append(p)
+        s= IMP.BipartiteNonbondedListScoreState(ps0, ps1)
+        m.add_score_state(s)
+        o= OnePair()
+        r= IMP.NonbondedRestraint(s, o)
+        m.add_restraint(r)
+        score= m.evaluate(False)
+        self.assertEqual(score, 25, "Wrong score")
 
-
 if __name__ == '__main__':
     unittest.main()
Index: kernel/include/IMP/restraints/BondDecoratorRestraint.h
===================================================================
--- kernel/include/IMP/restraints/BondDecoratorRestraint.h	(revision 0)
+++ kernel/include/IMP/restraints/BondDecoratorRestraint.h	(revision 0)
@@ -0,0 +1,52 @@
+/**
+ *  \file BondDecoratorRestraint.h   
+ *  \brief Apply a UnaryFunction to all bonded pairs.
+ *
+ *  Copyright 2007-8 Sali Lab. All rights reserved.
+ *
+ */
+
+#ifndef __IMP_BOND_DECORATOR_RESTRAINT_H
+#define __IMP_BOND_DECORATOR_RESTRAINT_H
+
+#include "../IMP_config.h"
+#include "../Restraint.h"
+
+#include <iostream>
+
+namespace IMP
+{
+
+class BondDecoratorListScoreState;
+class UnaryFunction;
+
+//! Restrain all pairs of non-bonded particles
+/**
+   This restraint currently only works for bonds which have their 
+   length set explicitly. Eventually we should add a table for standard
+   molecular bonds.
+
+   The bond stiffness is assumed to be 1 if it is not specified in
+   the bond. This can become a parameter eventually.
+ */
+class IMPDLLEXPORT BondDecoratorRestraint : public Restraint
+{
+public:
+  //! Create the bond restraint.
+  /** \param[in] bl The BondDecoratorListScoreState to use to get the list
+      of bonds.
+      \param[in] f The UnaryFunction to apply to the particles.
+   */
+  BondDecoratorRestraint(BondDecoratorListScoreState *nbl, UnaryFunction *f);
+  virtual ~BondDecoratorRestraint(){}
+
+  IMP_RESTRAINT("0.5", "Daniel Russel");
+
+protected:
+  BondDecoratorListScoreState *bl_;
+  std::auto_ptr<UnaryFunction> f_;
+};
+
+} // namespace IMP
+
+#endif  /* __IMP_BOND_DECORATOR_RESTRAINT_H */
Index: kernel/src/score_states/bonded_lists/BondDecoratorListScoreState.cpp
===================================================================
--- kernel/src/score_states/bonded_lists/BondDecoratorListScoreState.cpp	(revision 0)
+++ kernel/src/score_states/bonded_lists/BondDecoratorListScoreState.cpp	(revision 0)
@@ -0,0 +1,47 @@
+/**
+ *  \file BondDecoratorListScoreState.h    
+ *  \brief Allow iteration through pairs of a set of atoms.
+ *
+ *  Copyright 2007-8 Sali Lab. All rights reserved.
+ */
+#include "IMP/score_states/bonded_lists/BondDecoratorListScoreState.h"
+
+namespace IMP 
+{
+BondDecoratorListScoreState
+::BondDecoratorListScoreState(const Particles &ps): ps_(ps) {
+}
+
+void BondDecoratorListScoreState::update() {
+  bonds_.clear();
+  for (unsigned int i=0; i< ps_.size(); ++i) {
+    BondedDecorator di= BondedDecorator::cast(ps_[i]);
+    ParticleIndex pi= ps_[i]->get_index();
+    for (unsigned int j=0; j< di.get_number_of_bonds(); ++j) {
+      BondedDecorator dj= di.get_bonded(j);
+      if (di < dj) {
+        bonds_.push_back(di.get_bond(j));
+      }
+    }
+  }
+  IMP_LOG(VERBOSE, "Found " << bonds_.size() << " bonds"<< std::endl);
+}
+
+void BondDecoratorListScoreState::set_particles(const Particles &ps) {
+  ps_=ps;
+  bonds_.clear();
+}
+
+
+bool BondDecoratorListScoreState::are_bonded(Particle *a, Particle *b) const {
+  try {
+    BondedDecorator da= BondedDecorator::cast(a);
+    BondedDecorator db= BondedDecorator::cast(b);
+    return get_bond(da, db) != BondDecorator();
+  } catch (...) {
+    IMP_LOG(VERBOSE, "Exception thrown in are_bonded"<< std::endl);
+  }
+  return false;
+}
+
+}
Index: kernel/src/score_states/bonded_lists/SConscript
===================================================================
--- kernel/src/score_states/bonded_lists/SConscript	(revision 0)
+++ kernel/src/score_states/bonded_lists/SConscript	(revision 0)
@@ -0,0 +1,6 @@
+Import('env')
+
+files = ['BondDecoratorListScoreState.cpp']
+
+files = [File(x) for x in files]
+Return('files')
Index: kernel/src/decorators/bond_decorators.cpp
===================================================================
--- kernel/src/decorators/bond_decorators.cpp	(revision 338)
+++ kernel/src/decorators/bond_decorators.cpp	(working copy)
@@ -19,6 +19,7 @@
 FloatKey bond_length_key_;
 IntKey bond_type_key_;
 IntKey bond_order_key_;
+FloatKey bond_stiffness_key_;
 
 } // namespace internal
 
@@ -54,6 +55,8 @@
     internal::bond_graph_data_= internal::GraphData("bond");
     internal::bond_type_key_= IntKey("bond type");
     internal::bond_order_key_=IntKey("bond order");
+    internal::bond_length_key_=FloatKey("bond length");
+    internal::bond_stiffness_key_=FloatKey("bond stiffness");
     internal::bond_keys_initialized_=true;
   }
 }