Set<MultipleDeriv> DiffOpEvaluator
::backedDerivs(const MultipleDeriv& mu,
  const Set<MultipleDeriv>& W1, int verb) const
{
  Tabs tabs;
  SUNDANCE_MSG3(verb, tabs << "computing backed-out derivs for mu= " << mu
    << ", W1=" << W1);
  Set<MultipleDeriv> rtn;
  if (mu.order() != 0) 
  {
    const MultiIndex& alpha = expr()->mi();

    for (Set<MultipleDeriv>::const_iterator i=W1.begin(); i!=W1.end(); i++)
    {
      const MultipleDeriv& md = *i;
      TEUCHOS_TEST_FOR_EXCEPT(md.order() != 1);
      Deriv lambda = *(md.begin());
      if (lambda.isCoordDeriv()) continue;
      TEUCHOS_TEST_FOR_EXCEPT(!lambda.isFunctionalDeriv());
      FunctionIdentifier lambda_fid = lambda.fid();
      const MultiIndex& lambda_mi = lambda.opOnFunc().mi(); 
      for (MultipleDeriv::const_iterator j=mu.begin(); j!=mu.end(); j++)
      {
        const Deriv& d = *j;
        if (d.isCoordDeriv()) continue;
        FunctionIdentifier d_fid = d.fid();
        const MultiIndex& d_mi = d.opOnFunc().mi(); 
        if (d_fid != lambda_fid) continue;
        if (!(alpha + lambda_mi == d_mi)) continue;
        MultipleDeriv z = mu.factorOutDeriv(d);
        z.put(lambda);
        rtn.put(z);
      }
    }
  }
  SUNDANCE_MSG3(verb, tabs << "backed-out derivs = " << rtn);
  return rtn;
}
bool testVecFunction()
{
  bool pass = true;
  Tabs tab;
  int verb=1;

  /* make a vector function */
  int dim = 3;
  Expr u = new UnknownFunctionStub("u", 1, 3);
  Expr phi = new UnknownFunctionStub("u", 0, 1);
  Expr v = new TestFunctionStub("v", 1, 3);
  Expr alpha = new UnknownParameter("alpha");

  TEUCHOS_TEST_EQUALITY(u.size(), dim, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(v.size(), dim, Out::os(), pass);
  
  /* Verify that D_mi u fails for nonzero multiindex.  */
//  MultiIndex m1(0,1,0);
//  TEST_THROW(
//    funcDeriv(u, m1), pass
//    );
  
  
  Deriv d_du = funcDeriv(u);
  Deriv d_dAlpha = funcDeriv(alpha);
  Deriv d_dphi = funcDeriv(phi);
  Deriv d_dphi_x = d_dphi.derivWrtMultiIndex(MultiIndex(1,0,0));
  Deriv divU = divergenceDeriv(u);
  Deriv divV = divergenceDeriv(v);

  TEUCHOS_TEST_EQUALITY(divU.fid(), fid(u), Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.fid(), fid(alpha), Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking algSpec for parameter");
  TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isScalar(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isVector(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isNormal(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isCoordinateComponent(), false, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking algSpec for divergence");
  TEUCHOS_TEST_EQUALITY(divU.algSpec().isScalar(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.algSpec().isVector(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.algSpec().isNormal(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.algSpec().isCoordinateComponent(), false, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking algSpec for vector operative func");
  TEUCHOS_TEST_EQUALITY(d_du.algSpec().isScalar(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.algSpec().isVector(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.algSpec().isNormal(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.algSpec().isCoordinateComponent(), false, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking algSpec for scalar operative func");
  TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isScalar(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isVector(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isNormal(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isCoordinateComponent(), false, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking algSpec for d/d(Dx(phi))");
  TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isScalar(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isVector(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isNormal(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isCoordinateComponent(), true, Out::os(), pass);


  SUNDANCE_BANNER1(verb, tab, "checking distinction between functional and spatial derivs");
  TEUCHOS_TEST_EQUALITY(d_dAlpha.isFunctionalDeriv(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.isCoordDeriv(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.isFunctionalDeriv(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.isCoordDeriv(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.isFunctionalDeriv(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.isCoordDeriv(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.isFunctionalDeriv(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.isCoordDeriv(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.isFunctionalDeriv(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.isCoordDeriv(), false, Out::os(), pass);


  SUNDANCE_BANNER1(verb, tab, "checking identification of differentiation order");
  TEUCHOS_TEST_EQUALITY(divU.opOnFunc().derivOrder(), 1, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.opOnFunc().derivOrder(), 0, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.opOnFunc().derivOrder(), 0, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.opOnFunc().derivOrder(), 0, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.opOnFunc().derivOrder(), 1, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking identification of test and unk funcs");
  TEUCHOS_TEST_EQUALITY(d_du.isTestFunction(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.isUnknownFunction(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_du.isParameter(), false, Out::os(), pass);

  TEUCHOS_TEST_EQUALITY(d_dphi.isTestFunction(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.isUnknownFunction(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.isParameter(), false, Out::os(), pass);

  TEUCHOS_TEST_EQUALITY(d_dphi_x.isTestFunction(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi_x.isUnknownFunction(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dphi.isParameter(), false, Out::os(), pass);

  TEUCHOS_TEST_EQUALITY(divU.isTestFunction(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.isUnknownFunction(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.isParameter(), false, Out::os(), pass);

  TEUCHOS_TEST_EQUALITY(divV.isTestFunction(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divV.isUnknownFunction(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divV.isParameter(), false, Out::os(), pass);

  /* unknown parameters are both unknown and parameters */
  TEUCHOS_TEST_EQUALITY(d_dAlpha.isTestFunction(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.isUnknownFunction(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(d_dAlpha.isParameter(), true, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking identification of spatial operators acting on operative functions");

  TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isDivergence(), true, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isNormal(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isPartial(), false, Out::os(), pass);
  TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isIdentity(), false, Out::os(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking that asking for component information from a divergence throws an exception");

  TEST_THROW(divU.opOnFunc().normalDerivOrder(), pass);
  TEST_THROW(divU.opOnFunc().mi(), pass);

  SUNDANCE_BANNER1(verb, tab, "checking that applying a partial derivative to a divergence throws an exception");
  TEST_THROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(1,0,0)), pass);
  TEST_THROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(0,1,0)), pass);
  TEST_THROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(0,0,1)), pass);
  SUNDANCE_BANNER1(verb, tab, "checking that applying a zero-order partial derivative to a divergence does not throw an exception");
  TEST_NOTHROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(0,0,0)), pass);

  SUNDANCE_BANNER1(verb, tab, "checking that applying a partial derivative to a divergence throws an exception");
  TEST_THROW(divU.derivWrtMultiIndex(MultiIndex(1,0,0)), pass);
  TEST_THROW(divU.derivWrtMultiIndex(MultiIndex(0,1,0)), pass);
  TEST_THROW(divU.derivWrtMultiIndex(MultiIndex(0,0,1)), pass);
  SUNDANCE_BANNER1(verb, tab, "checking that applying a zero-order partial derivative to a divergence does not throw an exception");
  TEST_NOTHROW(divU.derivWrtMultiIndex(MultiIndex(0,0,0)), pass);


  SUNDANCE_BANNER1(verb, tab, "checking that applying a partial derivative to a parameter throws an exception");
  TEST_THROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(1,0,0)), pass);
  TEST_THROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(0,1,0)), pass);
  TEST_THROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(0,0,1)), pass);
  SUNDANCE_BANNER1(verb, tab, "checking that applying a zero-order partial derivative to a divergence does not throw an exception");
  TEST_NOTHROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(0,0,0)), pass);

  SUNDANCE_BANNER1(verb, tab, "all done!");

  return pass;
}