What is means for a particle to be inactive is not well defined at this point. My proposal would be that we define them to be permanently dead-- particles are made inactive by removing them from the Model.
When restraints encounter inactive particles, they should either: - if they act on bulk sets of particles, just remove the inactive particle from their list and go on. This would apply to the nonbonded list and list-based restraints - if they act on a constant number of particles, the InactiveParticleException should propagate. The thing holding the restraint can use the exception to destroy the restraint (maybe) or, probably better, just to kill the optimization.
The iterators provided by the model would skip inactive particles (and reference counting would ensure that the memory is reclaimed when everything is cleaned up), thereby allowing the optimizers to work when there are inactive particles.
Using this, you could, for example, maintain a dynamic set of particles by adding all new particles to the nonbonded list and know that all inactive particles will get cleaned up properly.
In order to make sure the reference counting works, Particles would get a new attribute type which is a pointer to another particle. Bonds and hierarchies would use this new attribute type.
Note that swig reference counting is pretty much useless, so there is no trivial way to ensure that all references held in python keep the respective bit of memory alive. Namely, if you get a particle back from the model or a restraint, this python object will not keep the corresponding C++ object alive. There are solutions to this problem, but I don't want to implement them now as they are a bit complicated. For now, the best solution might be to have the python wrapper print warnings when the dangerous functions are used.