Sundance::Map<Expr, int> Expr::getSumTree() const
{
  RCP<ScalarExpr> sThis = rcp_dynamic_cast<ScalarExpr>(ptr());

  TEUCHOS_TEST_FOR_EXCEPTION(sThis.get()==0, std::logic_error,
    "etSumTree() not defined for non-scalar expression "
    << toString());
  
  const SumExpr* s = dynamic_cast<const SumExpr*>(sThis.get());
  const UnaryMinus* u = dynamic_cast<const UnaryMinus*>(sThis.get());
  if (s != 0)
  {
    return s->getSumTree();
  }
  else if (u != 0)
  {
    Sundance::Map<Expr, int> rtn;
    rtn.put(u->arg(), -1);
    return rtn;
  }
  else
  {
    Sundance::Map<Expr, int> rtn;
    rtn.put(*this, 1);
    return rtn;
  }
  
}
void SumOfIntegrals::changeSign()
{
  Sundance::Map<RegionQuadCombo, Expr> newMap;
  for (Sundance::Map<RegionQuadCombo, Expr>::const_iterator 
         i=rqcToExprMap_.begin(); i!=rqcToExprMap_.end(); i++)
  {
    Expr e = i->second;
    newMap.put(i->first, -e);
  }
  rqcToExprMap_ = newMap;
}
void SumOfIntegrals::multiplyByConstant(const SpatiallyConstantExpr* expr) 
{
  double a = expr->value();
  Sundance::Map<RegionQuadCombo, Expr> newMap;
  for (Sundance::Map<RegionQuadCombo, Expr>::const_iterator 
         i=rqcToExprMap_.begin(); i!=rqcToExprMap_.end(); i++)
  {
    Expr e = i->second;
    newMap.put(i->first, a*e);
  }
  rqcToExprMap_ = newMap;
}
int factorial(const MultipleDeriv& ms)
{
  Sundance::Map<Deriv, int> counts;
    
  for (MultipleDeriv::const_iterator i=ms.begin(); i!=ms.end(); i++)
  {
    if (counts.containsKey(*i)) counts[*i]++;
    else counts.put(*i, 1);
  }

  int rtn = 1;
  for (Sundance::Map<Deriv, int>::const_iterator
         i=counts.begin(); i!=counts.end(); i++)
  {
    int f = 1;
    for (int j=1; j<=i->second; j++) f *= j;
    rtn *= f;
  }
  return rtn;
}
bool ReorderSum::doTransform(const RCP<ScalarExpr>& left, 
                             const RCP<ScalarExpr>& right,
                             int sign, RCP<ScalarExpr>& rtn) const
{
  TimeMonitor timer(reorderSumTimer());
  /* first we check to see whether the terms are already in order.
   * The left and right trees are already ordered, so that if the
   * first term on the right is after the last term on the left, the
   * combination of both is already ordered. In that case, nothing more needs
   * to be done. 
   */
  Expr L = Expr::handle(left);
  Expr R = Expr::handle(right);
  Sundance::Map<Expr, int> tree = L.getSumTree();
  Sundance::Map<Expr, int>::const_reverse_iterator iL = tree.rbegin();
  Expr endOfLeft = iL->first;
  Sundance::Map<Expr, int> rightTree = R.getSumTree();
  Sundance::Map<Expr, int>::const_iterator iR = rightTree.begin();
  Expr startOfRight = iR->first;

  if (endOfLeft.lessThan(startOfRight))
    {
      Tabs tab1;
      SUNDANCE_VERB_MEDIUM(tab1 << "Terms are already ordered, doing nothing");
      return false;
    }
  else
    {
      Tabs tab1;

      for (Map<Expr, int>::const_iterator i=rightTree.begin(); i!=rightTree.end(); i++)
        {
          int leftCount = 0;
          if (tree.containsKey(i->first))
            {
              leftCount = tree[i->first];
            }
          int count = leftCount + sign * i->second;
          tree.put(i->first, count);
        }
      SUNDANCE_VERB_MEDIUM(tab1 << "Ordered terms are: " << tree);      


      Expr sum = new ZeroExpr();

      /* add up all terms. If no terms are left after cancellations, the result will 
       * be zero. */
      for (Map<Expr, int>::const_iterator i=tree.begin(); i!=tree.end(); i++)
        {
          const Expr& term = i->first;
          int count = i->second;
          if (count==0) continue;
          if (count==1) sum = sum + term;
          else if (count==-1) sum = sum - term;
          else sum = sum + count*term;
        }
      
      rtn = getScalar(sum);
      return true;
    }
}