Set<MultipleDeriv> applyTx(const Set<MultipleDeriv>& s,
  const MultiIndex& x)
{
  Set<MultipleDeriv> rtn;

  for (Set<MultipleDeriv>::const_iterator i=s.begin(); i!=s.end(); i++)
  {
    const MultipleDeriv& md = *i;
    for (MultipleDeriv::const_iterator j=md.begin(); j!=md.end(); j++)
    {
      const Deriv& d = *j;
      if (d.isFunctionalDeriv())
      {
        const MultiIndex& mi = d.opOnFunc().mi();
        MultiIndex miNew = mi+x;
        if (miNew.isValid())
        {
          Deriv dNew = d.derivWrtMultiIndex(miNew);
          MultipleDeriv mdNew = md;
          mdNew.erase(mdNew.find(d));
          mdNew.put(dNew);
          rtn.put(mdNew);
        }
      }
    }
  }
  return rtn;
}
MultipleDeriv MultipleDeriv::factorOutDeriv(const Deriv& x) const
{
  MultipleDeriv rtn = *this;

  MultipleDeriv::iterator i = rtn.find(x);

  /* remove a single copy of the given derivative */
  if (i != rtn.end()) rtn.erase(i);

  if (rtn.size() == this->size()) return MultipleDeriv();

  return rtn;
}
MultipleDeriv MultipleDeriv::factorOutDeriv(const MultipleDeriv& x) const
{
  MultipleDeriv rtn = *this;

  for (MultipleDeriv::const_iterator i=x.begin(); i!=x.end(); i++)
  {
    MultipleDeriv::iterator j = rtn.find(*i);

    /* remove a single copy of the given derivative */
    if (j != rtn.end()) rtn.erase(j);
  }

  if (rtn.size() == this->size()) return MultipleDeriv();
  return rtn;
}