Repository: Pyomo/pyomo

Issue:
Different results when using Pyomo on master vs. IDAES branch. 
A variable that is calculated is off by a factor of 1000 when using Pyomo installed from the main branch vs. Pyomo installed from the IDAES branch. To run the sample problem, please follow the steps below:

1. Download this branch: https://github.com/IDAES/idaes/tree/pyomo_version_error
2. Move to directory (idaes/contrib/properties/iapws95/ ) and run the following to compile the IAPWS prop pack:
      (i) make
3. Move to directory (examples/contrib/properties/iapws95/) and run the flash4.py file. 

Depending on the Pyomo version installed (master vs. IDAES), you will notice a difference in the value of the variable "enth_mol" in the "prop" block. If using the Pyomo - IDAES version this value will be 20958 but if using Pyomo - master branch version, this value will be 20.958.  The correct value is 20958 as obtained with the IDAES branch. 

John Eslick was seeing some similar errors with other simulations. Let us know if you need more information or help in running the examples. 



Discussion:
@jghouse88: To confirm, which hash (commit) on the master branch are you testing?
@jsiirola It was the latest commit 8002169 that was merged 22 hours ago. For the IDAES branch, it is  f8e1efa merged 8 days ago. 
@jghouse88 not sure this matters but just so we can be sure we're testing the same thing, which version of Python are you using?
@blnicho It is 2.7.13.  
@whart222 can you take a look at this and make sure it is not related to expr_dev?

Resolving patch:
diff --git a/pyomo/repn/standard_repn.py b/pyomo/repn/standard_repn.py
--- a/pyomo/repn/standard_repn.py
+++ b/pyomo/repn/standard_repn.py
@@ -410,7 +410,7 @@ def __init__(self, constant=0, nonl=0, linear=None, quadratic=None):
         #    self.quadratic = quadratic
 
     def __str__(self):          #pragma: nocover
-        return "Const:\t%f\nLinear:\t%s\nQuadratic:\t%s\nNonlinear:\t%s" % (self.constant, str(self.linear), str(self.quadratic), str(self.nonl))
+        return "Const:\t%s\nLinear:\t%s\nQuadratic:\t%s\nNonlinear:\t%s" % (str(self.constant), str(self.linear), str(self.quadratic), str(self.nonl))
 
 class ResultsWithoutQuadratics(object):
     __slot__ = ('const', 'nonl', 'linear')
@@ -425,7 +425,7 @@ def __init__(self, constant=0, nonl=0, linear=None):
         #    self.linear = linear
 
     def __str__(self):          #pragma: nocover
-        return "Const:\t%f\nLinear:\t%s\nNonlinear:\t%s" % (self.constant, str(self.linear), str(self.nonl))
+        return "Const:\t%s\nLinear:\t%s\nNonlinear:\t%s" % (str(self.constant), str(self.linear), str(self.nonl))
 
 Results = ResultsWithQuadratics
 
@@ -511,7 +511,7 @@ def _collect_term(exp, multiplier, idMap, compute_values, verbose, quadratic):
     # LHS is a numeric value
     #
     if exp._args_[0].__class__ in native_numeric_types:
-        if exp._args_[0] == 0:
+        if exp._args_[0] == 0:                          # TODO: coverage?
             return Results()
         return _collect_standard_repn(exp._args_[1], multiplier * exp._args_[0], idMap, 
                                   compute_values, verbose, quadratic)
@@ -534,7 +534,7 @@ def _collect_prod(exp, multiplier, idMap, compute_values, verbose, quadratic):
     # LHS is a numeric value
     #
     if exp._args_[0].__class__ in native_numeric_types:
-        if exp._args_[0] == 0:
+        if exp._args_[0] == 0:                          # TODO: coverage?
             return Results()
         return _collect_standard_repn(exp._args_[1], multiplier * exp._args_[0], idMap, 
                                   compute_values, verbose, quadratic)
@@ -542,7 +542,7 @@ def _collect_prod(exp, multiplier, idMap, compute_values, verbose, quadratic):
     # RHS is a numeric value
     #
     if exp._args_[1].__class__ in native_numeric_types:
-        if exp._args_[1] == 0:
+        if exp._args_[1] == 0:                          # TODO: coverage?
             return Results()
         return _collect_standard_repn(exp._args_[0], multiplier * exp._args_[1], idMap, 
                                   compute_values, verbose, quadratic)
@@ -589,7 +589,7 @@ def _collect_prod(exp, multiplier, idMap, compute_values, verbose, quadratic):
             return Results()
         if compute_values:
             val = value(lhs.constant)
-            if val == 0:
+            if val == 0:                            # TODO: coverage?
                 return Results()
             return _collect_standard_repn(exp._args_[1], multiplier*val, idMap, 
                                   compute_values, verbose, quadratic)
@@ -599,15 +599,7 @@ def _collect_prod(exp, multiplier, idMap, compute_values, verbose, quadratic):
     #
     # Collect RHS
     #
-    if exp._args_[1].__class__ in native_numeric_types:
-        rhs = Results(constant=exp._args_[1])
-    elif not exp._args_[1].is_potentially_variable():
-        if compute_values:
-            rhs = Results(constant=value(exp._args_[1]))
-        else:
-            rhs = Results(constant=exp._args_[1])
-    else:
-        rhs = _collect_standard_repn(exp._args_[1], 1, idMap, 
+    rhs = _collect_standard_repn(exp._args_[1], 1, idMap, 
                                   compute_values, verbose, quadratic)
     rhs_nonl_None = rhs.nonl.__class__ in native_numeric_types and rhs.nonl == 0
     #
@@ -624,7 +616,7 @@ def _collect_prod(exp, multiplier, idMap, compute_values, verbose, quadratic):
     # If not collecting quadratic terms and both terms are linear, then simply return the nonlinear expression
     #
     if not quadratic and len(lhs.linear) > 0 and len(rhs.linear) > 0:
-        # NOTE: We treat a product of linear terms as nonlinear unless quadratic==2
+        # NOTE: We treat a product of linear terms as nonlinear unless quadratic is True
         return Results(nonl=multiplier*exp)
 
     ans = Results()
@@ -651,21 +643,17 @@ def _collect_prod(exp, multiplier, idMap, compute_values, verbose, quadratic):
                     ans.quadratic[key] = multiplier*coef*rhs.constant
         for lkey, lcoef in six.iteritems(lhs.linear):
             for rkey, rcoef in six.iteritems(rhs.linear):
-                if lkey <= rkey:
-                    ans.quadratic[lkey,rkey] = multiplier*lcoef*rcoef
+                ndx = (lkey, rkey) if lkey <= rkey else (rkey, lkey)
+                if ndx in ans.quadratic:
+                    ans.quadratic[ndx] += multiplier*lcoef*rcoef
                 else:
-                    ans.quadratic[rkey,lkey] = multiplier*lcoef*rcoef
+                    ans.quadratic[ndx] = multiplier*lcoef*rcoef
         # TODO - Use quicksum here?
         el_linear = multiplier*sum(coef*idMap[key] for key, coef in six.iteritems(lhs.linear))
         er_linear = multiplier*sum(coef*idMap[key] for key, coef in six.iteritems(rhs.linear))
         el_quadratic = multiplier*sum(coef*idMap[key[0]]*idMap[key[1]] for key, coef in six.iteritems(lhs.quadratic))
         er_quadratic = multiplier*sum(coef*idMap[key[0]]*idMap[key[1]] for key, coef in six.iteritems(rhs.quadratic))
         ans.nonl += el_linear*er_quadratic + el_quadratic*er_linear
-    elif len(lhs.linear) + len(rhs.linear) > 1:
-        return Results(nonl=multiplier*exp)
-        #el_linear = multiplier*sum(coef*idMap[key] for key, coef in six.iteritems(lhs.linear))
-        #er_linear = multiplier*sum(coef*idMap[key] for key, coef in six.iteritems(rhs.linear))
-        #ans.nonl += el_linear*er_linear
 
     return ans
 
@@ -687,7 +675,7 @@ def _collect_var(exp, multiplier, idMap, compute_values, verbose, quadratic):
             idMap[None][id_] = key
             idMap[key] = exp
         if key in ans.linear:
-            ans.linear[key] += multiplier
+            ans.linear[key] += multiplier       # TODO: coverage?
         else:
             ans.linear[key] = multiplier
 
@@ -776,7 +764,7 @@ def _collect_pow(exp, multiplier, idMap, compute_values, verbose, quadratic):
     return Results(nonl=multiplier*exp)
 
 def _collect_reciprocal(exp, multiplier, idMap, compute_values, verbose, quadratic):
-    if exp._args_[0].__class__ in native_numeric_types or not exp._args_[0].is_potentially_variable():
+    if exp._args_[0].__class__ in native_numeric_types or not exp._args_[0].is_potentially_variable():  # TODO: coverage?
         if compute_values:
             denom = 1.0 * value(exp._args_[0])
         else:
@@ -788,11 +776,11 @@ def _collect_reciprocal(exp, multiplier, idMap, compute_values, verbose, quadrat
         else:
             denom = 1.0*res.constant
     if denom.__class__ in native_numeric_types and denom == 0:
-        raise ZeroDivisionError()
+        raise ZeroDivisionError
     return Results(constant=multiplier/denom)
    
 def _collect_branching_expr(exp, multiplier, idMap, compute_values, verbose, quadratic):
-    if exp._if.__class__ in native_numeric_types:
+    if exp._if.__class__ in native_numeric_types:           # TODO: coverage?
         if_val = exp._if
     elif not exp._if.is_potentially_variable():
         if compute_values:
@@ -803,11 +791,17 @@ def _collect_branching_expr(exp, multiplier, idMap, compute_values, verbose, qua
         res = _collect_standard_repn(exp._if, 1, idMap, compute_values, verbose, quadratic)
         if not (res.nonl.__class__ in native_numeric_types and res.nonl == 0) or len(res.linear) > 0 or (quadratic and len(res.quadratic) > 0):
             return Results(nonl=multiplier*exp)
-        else:
+        elif res.constant.__class__ in native_numeric_types:
             if_val = res.constant
+        else:
+            return Results(constant=multiplier*exp)
     if if_val:
+        if exp._then.__class__ in native_numeric_types:
+            return Results(constant=multiplier*exp._then)
         return _collect_standard_repn(exp._then, multiplier, idMap, compute_values, verbose, quadratic)
     else:
+        if exp._else.__class__ in native_numeric_types:
+            return Results(constant=multiplier*exp._else)
         return _collect_standard_repn(exp._else, multiplier, idMap, compute_values, verbose, quadratic)
 
 def _collect_nonl(exp, multiplier, idMap, compute_values, verbose, quadratic):
@@ -822,20 +816,23 @@ def _collect_nonl(exp, multiplier, idMap, compute_values, verbose, quadratic):
 def _collect_negation(exp, multiplier, idMap, compute_values, verbose, quadratic):
     return _collect_standard_repn(exp._args_[0], -1*multiplier, idMap, compute_values, verbose, quadratic)
 
+#
+# TODO - Verify if code is used
+#
 def _collect_const(exp, multiplier, idMap, compute_values, verbose, quadratic):
     if compute_values:
-        return Results(constant=value(exp))
+        return Results(constant=multiplier*value(exp))
     else:
-        return Results(constant=exp)
+        return Results(constant=multiplier*exp)
 
 def _collect_identity(exp, multiplier, idMap, compute_values, verbose, quadratic):
     if exp._args_[0].__class__ in native_numeric_types:
-        return Results(constant=exp._args_[0])
+        return Results(constant=multiplier*exp._args_[0])
     if not exp._args_[0].is_potentially_variable():
         if compute_values:
-            return Results(constant=value(exp._args_[0]))
+            return Results(constant=multiplier*value(exp._args_[0]))
         else:
-            return Results(constant=exp._args_[0])
+            return Results(constant=multiplier*exp._args_[0])
     return _collect_standard_repn(exp.expr, multiplier, idMap, compute_values, verbose, quadratic)
 
 def _collect_linear(exp, multiplier, idMap, compute_values, verbose, quadratic):
@@ -875,42 +872,10 @@ def _collect_comparison(exp, multiplier, idMap, compute_values, verbose, quadrat
     return Results(nonl=multiplier*exp)
     
 def _collect_external_fn(exp, multiplier, idMap, compute_values, verbose, quadratic):
+    if compute_values and exp.is_fixed():
+        return Results(nonl=multiplier*value(exp))
     return Results(nonl=multiplier*exp)
     
-def _collect_linear_sum(exp, multiplier, idMap, compute_values, verbose, quadratic):
-    ans = Results()
-    varkeys = idMap[None]
-
-    for e_ in itertools.islice(exp._args_, exp.nargs()):
-        c,v = e_
-        if not v is None:
-            if v.fixed:
-                if compute_values:
-                    ans.constant += multiplier*c*v.value
-                else:
-                    ans.constant += multiplier*c*v
-            else:
-                id_ = id(v)
-                if id_ in varkeys:
-                    key = varkeys[id_]
-                else:
-                    key = len(idMap) - 1
-                    varkeys[id_] = key
-                    idMap[key] = v
-                if key in ans.linear:
-                    ans.linear[key] += multiplier*c
-                else:
-                    ans.linear[key] = multiplier*c
-        elif c.__class__ in native_numeric_types:
-            ans.constant += multiplier*c
-        else:       # not c.is_potentially_variable()
-            if compute_values:
-                ans.constant += multiplier * value(c)
-            else:
-                ans.constant += multiplier * c
-
-    return ans
-
 
 _repn_collectors = {
     EXPR.SumExpression                          : _collect_sum,
@@ -927,7 +892,6 @@ def _collect_linear_sum(exp, multiplier, idMap, compute_values, verbose, quadrat
     EXPR.RangedExpression                       : _collect_comparison,
     EXPR.EqualityExpression                     : _collect_comparison,
     EXPR.ExternalFunctionExpression             : _collect_external_fn,
-    #EXPR.LinearSumExpression               : _collect_linear_sum,
     #_ConnectorData          : _collect_linear_connector,
     #SimpleConnector         : _collect_linear_connector,
     #param._ParamData        : _collect_linear_const,
@@ -954,18 +918,23 @@ def _collect_linear_sum(exp, multiplier, idMap, compute_values, verbose, quadrat
 
 def _collect_standard_repn(exp, multiplier, idMap, 
                                       compute_values, verbose, quadratic):
+    fn = _repn_collectors.get(exp.__class__, None)
+    if fn is not None:
+        return fn(exp, multiplier, idMap, compute_values, verbose, quadratic)
+    #
+    # These are types that might be extended using duck typing.
+    #
     try:
-        return _repn_collectors[exp.__class__](exp, multiplier, idMap, 
-                                          compute_values, verbose, quadratic)
-    except KeyError:
-        #
-        # These are types that might be extended using duck typing.
-        #
         if exp.is_variable_type():
-            return _collect_var(exp, multiplier, idMap, compute_values, verbose, quadratic)
+            fn = _collect_var
         if exp.is_named_expression_type():
-            return _collect_identity(exp, multiplier, idMap, compute_values, verbose, quadratic)
-        raise ValueError( "Unexpected expression (type %s)" % type(exp).__name__)
+            fn = _collect_identity
+    except AttributeError:                                                          # TODO: coverage?
+        pass
+    if fn is not None:
+        _repn_collectors[exp.__class__] = fn
+        return fn(exp, multiplier, idMap, compute_values, verbose, quadratic)
+    raise ValueError( "Unexpected expression (type %s)" % type(exp).__name__)       # TODO: coverage?
 
 
 def _generate_standard_repn(expr, idMap=None, compute_values=True, verbose=False, quadratic=True, repn=None):
@@ -993,7 +962,7 @@ def _generate_standard_repn(expr, idMap=None, compute_values=True, verbose=False
         if val.__class__ in native_numeric_types:
             if val == 0:
                 continue
-        elif val.is_constant():
+        elif val.is_constant():         # TODO: coverage?
             if value(val) == 0:
                 continue
         v.append(idMap[key])
@@ -1007,9 +976,9 @@ def _generate_standard_repn(expr, idMap=None, compute_values=True, verbose=False
         for key in ans.quadratic:
             val = ans.quadratic[key]
             if val.__class__ in native_numeric_types:
-                if val == 0:
+                if val == 0:            # TODO: coverage?
                     continue
-            elif val.is_constant():
+            elif val.is_constant():     # TODO: coverage?
                 if value(val) == 0:
                     continue
             repn.quadratic_vars.append( (idMap[key[0]],idMap[key[1]]) )
@@ -1338,17 +1307,22 @@ def _linear_collect_pow(exp, multiplier, idMap, compute_values, verbose, coef):
 
 
 def _collect_linear_standard_repn(exp, multiplier, idMap, compute_values, verbose, coefs):
+    fn = _linear_repn_collectors.get(exp.__class__, None)
+    if fn is not None:
+        return fn(exp, multiplier, idMap, compute_values, verbose, coefs)
+    #
+    # These are types that might be extended using duck typing.
+    #
     try:
-        return _linear_repn_collectors[exp.__class__](exp, multiplier, idMap, compute_values, verbose, coefs)
-    except KeyError:
-        #
-        # These are types that might be extended using duck typing.
-        #
         if exp.is_variable_type():
-            return _linear_collect_var(exp, multiplier, idMap, compute_values, verbose, coefs)
+            fn = _linear_collect_var
         if exp.is_named_expression_type():
-            return _linear_collect_identity(exp, multiplier, idMap, compute_values, verbose, coefs)
-        raise ValueError( "Unexpected expression (type %s)" % type(exp).__name__)
+            fn = _linear_collect_identity
+    except AttributeError:
+        pass
+    if fn is not None:
+        return fn(exp, multiplier, idMap, compute_values, verbose, coefs)
+    raise ValueError( "Unexpected expression (type %s)" % type(exp).__name__)
 
 def _generate_linear_standard_repn(expr, idMap=None, compute_values=True, verbose=False, repn=None):
     coef = {None:0}


Test patch:
diff --git a/pyomo/repn/tests/test_standard.py b/pyomo/repn/tests/test_standard.py
--- a/pyomo/repn/tests/test_standard.py
+++ b/pyomo/repn/tests/test_standard.py
@@ -24,6 +24,7 @@
 from pyomo.repn import *
 from pyomo.environ import *
 from pyomo.core.base.numvalue import native_numeric_types
+from pyomo.core.kernel import expression, variable
 
 from six import iteritems
 from six.moves import range
@@ -56,7 +57,7 @@ def repn_to_dict(repn):
     return result
 
 
-class TestSimple(unittest.TestCase):
+class Test(unittest.TestCase):
 
     def test_number(self):
         # 1.0
@@ -3579,6 +3580,516 @@ def test_ExprIf(self):
         baseline = { id(rep.linear_vars[0]):1 }
         self.assertEqual(baseline, repn_to_dict(rep))
 
+    def test_expr_identity1(self):
+        m = ConcreteModel()
+        m.p = Param(mutable=True, initialize=2)
+        m.e = Expression(expr=m.p)
+
+        e = 1000*m.e
+
+        rep = generate_standard_repn(e, compute_values=True)
+        #
+        self.assertTrue( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 0 )
+        self.assertTrue( rep.is_constant() )
+        self.assertTrue( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertFalse( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 0)
+        self.assertTrue(len(rep.linear_coefs) == 0)
+        self.assertTrue(len(rep.quadratic_vars) == 0)
+        self.assertTrue(len(rep.quadratic_coefs) == 0)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { None:2000 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        rep = generate_standard_repn(e, compute_values=False)
+        #
+        self.assertTrue( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 0 )
+        self.assertTrue( rep.is_constant() )
+        self.assertTrue( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertFalse( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 0)
+        self.assertTrue(len(rep.linear_coefs) == 0)
+        self.assertTrue(len(rep.quadratic_vars) == 0)
+        self.assertTrue(len(rep.quadratic_coefs) == 0)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { None:2000 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+    def test_expr_identity2(self):
+        o = expression()
+        o.expr = 2
+
+        e = 1000*o
+
+        rep = generate_standard_repn(e)
+        #
+        self.assertTrue( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 0 )
+        self.assertTrue( rep.is_constant() )
+        self.assertTrue( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertFalse( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 0)
+        self.assertTrue(len(rep.linear_coefs) == 0)
+        self.assertTrue(len(rep.quadratic_vars) == 0)
+        self.assertTrue(len(rep.quadratic_coefs) == 0)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { None:2000 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+    def test_expr_identity3(self):
+        m = ConcreteModel()
+        m.v = Var(initialize=2)
+        m.e = Expression(expr=m.v)
+
+        e = 1000*m.e
+
+        rep = generate_standard_repn(e)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 1 )
+        self.assertFalse( rep.is_constant() )
+        self.assertTrue( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertFalse( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 1)
+        self.assertTrue(len(rep.linear_coefs) == 1)
+        self.assertTrue(len(rep.quadratic_vars) == 0)
+        self.assertTrue(len(rep.quadratic_coefs) == 0)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { id(m.v):1000 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+    def test_expr_const1(self):
+        o = expression()
+        o.expr = as_numeric(2)
+
+        e = 1000*o
+
+        rep = generate_standard_repn(e, compute_values=True)
+        #
+        self.assertTrue( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 0 )
+        self.assertTrue( rep.is_constant() )
+        self.assertTrue( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertFalse( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 0)
+        self.assertTrue(len(rep.linear_coefs) == 0)
+        self.assertTrue(len(rep.quadratic_vars) == 0)
+        self.assertTrue(len(rep.quadratic_coefs) == 0)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { None:2000 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+    def test_to_expression1(self):
+        m = ConcreteModel()
+        m.A = RangeSet(5)
+        m.v = Var(m.A)
+        m.p = Param(m.A, initialize={1:-2, 2:-1, 3:0, 4:1, 5:2})
+
+        e = sum(m.v[i] for i in m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "v[1] + v[2] + v[3] + v[4] + v[5]")
+        
+        e = sum(m.p[i]*m.v[i] for i in m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "-2*v[1] - v[2] + v[4] + 2*v[5]")
+        
+    def test_to_expression2(self):
+        m = ConcreteModel()
+        m.A = RangeSet(5)
+        m.v = Var(m.A)
+        m.p = Param(m.A, initialize={1:-2, 2:-1, 3:0, 4:1, 5:2}, mutable=True)
+
+        e = sum(m.p[i]*m.v[i] for i in m.v)
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p[1]*v[1] + p[2]*v[2] + p[3]*v[3] + p[4]*v[4] + p[5]*v[5]")
+        
+    def test_to_expression3(self):
+        m = ConcreteModel()
+        m.A = RangeSet(5)
+        m.v = Var(m.A)
+        m.p = Param(m.A, initialize={1:-2, 2:-1, 3:0, 4:1, 5:2})
+
+        e = sum(m.v[i]**2 for i in m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "v[1]**2 + v[2]**2 + v[3]**2 + v[4]**2 + v[5]**2")
+        
+        e = sum(m.p[i]*m.v[i]**2 for i in m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "-2*v[1]**2 - v[2]**2 + v[4]**2 + 2*v[5]**2")
+        
+        e = m.v[1]*m.v[2] + m.v[2]*m.v[3]
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "v[1]*v[2] + v[2]*v[3]")
+        
+    def test_to_expression4(self):
+        m = ConcreteModel()
+        m.A = RangeSet(3)
+        m.v = Var(m.A)
+        m.p = Param(m.A, initialize={1:-1, 2:0, 3:1}, mutable=True)
+
+        e = sum(m.p[i]*m.v[i]**2 for i in m.v)
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p[1]*v[1]**2 + p[2]*v[2]**2 + p[3]*v[3]**2")
+
+        e = sin(m.v[1])
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "sin(v[1])")
+
+    def test_nonlinear_sum(self):
+        m = ConcreteModel()
+        m.v = Var()
+
+        e = 10*(sin(m.v) + cos(m.v))
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "10*sin(v) + 10*cos(v)")
+        
+        e = 10*(1 + sin(m.v))
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "10 + 10*sin(v)")
+        
+    def test_product1(self):
+        m = ConcreteModel()
+        m.v = Var()
+        m.p = Param(mutable=True, initialize=0)
+
+        e = m.p*(1+m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p + p*v")
+       
+        e = (1+m.v)*m.p
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p + p*v")
+       
+        m.p.value = 1 
+
+        e = m.p*(1+m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1 + v")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p + p*v")
+       
+        e = (1+m.v)*m.p
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1 + v")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p + p*v")
+     
+    def test_product2(self): 
+        m = ConcreteModel()
+        m.v = Var(initialize=2)
+        m.w = Var(initialize=3)
+        m.v.fixed = True
+        m.w.fixed = True
+
+        e = m.v*m.w
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "6")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "v*w")
+         
+        e = m.w*m.v
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "6")
+
+        m.v.value = 0
+
+        e = m.v*m.w
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "v*w")
+         
+        e = m.w*m.v
+        m.w.fixed = False
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+
+    def test_product3(self): 
+        m = ConcreteModel()
+        m.v = Var(initialize=2)
+        m.w = Var(initialize=3)
+
+        e = sin(m.v)*m.w
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "sin(v)*w")
+
+        e = m.w*sin(m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "w*sin(v)")
+
+    def test_product4(self): 
+        m = ConcreteModel()
+        m.v = Var(initialize=2)
+        m.w = Var(initialize=3)
+
+        e = (1 + m.v + m.w)*(m.v + m.w)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "v + w + v**2 + 2*v*w + w**2")
+        rep = generate_standard_repn(e, compute_values=True, quadratic=False)
+        self.assertEqual(str(rep.to_expression()), "(1 + v + w)*(v + w)")
+
+        e = (1 + m.v + m.w + m.v**2)*(m.v + m.w + m.v**2)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "v + w + 2*v**2 + 2*v*w + w**2 + (v + w)*v*v + v*v*(v + w)")
+        rep = generate_standard_repn(e, compute_values=True, quadratic=False)
+        self.assertEqual(str(rep.to_expression()), "(1 + v + w + v**2)*(v + w + v**2)")
+
+        e = (m.v + m.w + m.v**2)*(1 + m.v + m.w + m.v**2)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "v + w + 2*v**2 + 2*v*w + w**2 + (v + w)*v*v + v*v*(v + w)")
+        rep = generate_standard_repn(e, compute_values=True, quadratic=False)
+        self.assertEqual(str(rep.to_expression()), "(v + w + v**2)*(1 + v + w + v**2)")
+
+        e = (1 + m.v + m.w + m.v**2)*(1 + m.v + m.w + m.v**2)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1 + 2*v + 2*w + 3*v**2 + 2*v*w + w**2 + (v + w)*v*v + v*v*(v + w)")
+        rep = generate_standard_repn(e, compute_values=True, quadratic=False)
+        self.assertEqual(str(rep.to_expression()), "(1 + v + w + v**2)*(1 + v + w + v**2)")
+
+    def test_product5(self): 
+        m = ConcreteModel()
+        m.v = Var(initialize=2)
+        m.w = Var(initialize=3)
+
+        e = (1 + m.v)*(1 + m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1 + 2*v + v**2")
+        rep = generate_standard_repn(e, compute_values=True, quadratic=False)
+        self.assertEqual(str(rep.to_expression()), "(1 + v)*(1 + v)")
+
+    def test_vars(self): 
+        m = ConcreteModel()
+        m.v = Var(initialize=2)
+        m.w = Var(initialize=3)
+
+        e = sin(m.v) + m.v + 2*m.v
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "3*v + sin(v)")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "3*v + sin(v)")
+
+    def test_reciprocal(self):
+        m = ConcreteModel()
+        m.v = Var(initialize=6)
+        m.w = Var(initialize=0)
+        m.p = Param(mutable=True, initialize=0.5)
+
+        e = sin(m.v)/m.p
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "(1/p)*sin(v)")
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "2.0*sin(v)")
+
+        e = m.p/sin(m.v)
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "p*(1/sin(v))")
+
+        m.w.fixed=True
+        e = m.v/m.w
+        try:
+            rep = generate_standard_repn(e, compute_values=True)
+            self.fail("Expected division by zero")
+        except ZeroDivisionError:
+            pass
+
+    def test_IfThen(self):
+        m = ConcreteModel()
+        m.w = Var(initialize=1)
+        m.v = Var(initialize=0)
+        m.v.fixed = True
+        m.p = Param(mutable=True, initialize=1)
+
+        e = Expr_if(1, 1, m.w)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1")
+
+        e = Expr_if(1, m.w, 0)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "w")
+
+        e = Expr_if(not m.p, 1, 0)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "Expr_if( ( 0.0 ), then=( 1 ), else=( 0 ) )")
+
+        e = Expr_if(not m.p, 1, m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "Expr_if( ( 0.0 ), then=( 1 ), else=( v ) )")
+
+        e = Expr_if(m.v, 1, 0)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "Expr_if( ( v ), then=( 1 ), else=( 0 ) )")
+
+        e = Expr_if(m.w, 1, 0)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "Expr_if( ( w ), then=( 1 ), else=( 0 ) )")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "Expr_if( ( w ), then=( 1 ), else=( 0 ) )")
+
+    def test_nonl(self):
+        m = ConcreteModel()
+        m.w = Var(initialize=0)
+
+        e = 1 + sin(m.w)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1 + sin(w)")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "1 + sin(w)")
+
+        m.w.fixed = True
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "1.0")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "1 + sin(w)")
+
+    def test_linear1(self):
+        m = ConcreteModel()
+        m.A = RangeSet(5)
+        m.v = Var(m.A, initialize=1)
+        m.p = Param(m.A, initialize={1:-2, 2:-1, 3:0, 4:1, 5:2})
+
+        e = summation(m.v) + sum_product(m.p, m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "- v[1] + v[3] + 2*v[4] + 3*v[5]")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "- v[1] + v[3] + 2*v[4] + 3*v[5]")
+
+        m.v[1].fixed=True
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "2 + v[3] + 2*v[4] + 3*v[5]")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "v[1] + v[1] + v[3] + 2*v[4] + 3*v[5]")
+
+    def test_linear2(self):
+        m = ConcreteModel()
+        m.A = RangeSet(5)
+        m.v = Var(m.A, initialize=1)
+        m.p = Param(m.A, initialize={1:-2, 2:-1, 3:0, 4:1, 5:2})
+
+        e = quicksum(m.p[i]*m.v[1] for i in m.p) + summation(m.p, m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "-2*v[1] - v[2] + v[4] + 2*v[5]")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "-2*v[1] - v[2] + v[4] + 2*v[5]")
+
+    def test_quadraticX1(self):
+        m = ConcreteModel()
+        m.A = RangeSet(5)
+        m.v = Var(m.A, initialize=1)
+        m.p = Param(m.A, initialize={1:-2, 2:-1, 3:0, 4:1, 5:2}, mutable=True)
+
+        e = sum(m.p[i]*m.v[i]**2 for i in m.A)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "-2*v[1]**2 - v[2]**2 + v[4]**2 + 2*v[5]**2")
+        #rep = generate_standard_repn(e, compute_values=False)
+        #self.assertEqual(str(rep.to_expression()), "-2*v[1]**2 - v[2]**2 + v[4]**2 + 2*v[5]**2")
+
+        m.v[1].fixed=True
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "-2 - v[2]**2 + v[4]**2 + 2*v[5]**2")
+        #rep = generate_standard_repn(e, compute_values=False)
+        #self.assertEqual(str(rep.to_expression()), "-2*v[1]*v[1] - v[2]**2 + v[4]**2 + 2*v[5]**2")
+
+    def test_relational(self):
+        m = ConcreteModel()
+        m.v = Var()
+        m.w = Var()
+
+        e = m.v + m.w >= 2
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "2.0  <=  v + w")
+
+    def test_external_fn(self):
+        def _g(*args):
+            return len(args)
+
+        m = ConcreteModel()
+        m.v = Var(initialize=1)
+        m.v.fixed = True
+        m.g = ExternalFunction(_g)
+
+        e = 100*m.g(1,2.0,'3')
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "300")
+        rep = generate_standard_repn(e, compute_values=False)
+        # The function ID is inconsistent, so we don't do a test
+        #self.assertEqual(str(rep.to_expression()), "100*g(0, 1, 2.0, '3')")
+
+        e = 100*m.g(1,2.0,'3',m.v)
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "400")
+        rep = generate_standard_repn(e, compute_values=False)
+        # The function ID is inconsistent, so we don't do a test
+        #self.assertEqual(str(rep.to_expression()), "100*g(0, 1, 2.0, '3', v)")
+
+    def test_ducktyping(self):
+        class vtype(variable):
+            pass
+        class Etype(expression):
+            pass
+
+        E = Etype()
+        v = vtype()
+        v.value = 2
+        v.fixed = True
+
+        e = v
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "2")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "<vtype>")
+
+        e = 1 + v
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "3")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "1 + <vtype>")
+
+        e = (1 + v)*v
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "6")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "(1 + <vtype>)*<vtype>")
+
+        E.expr = v
+        e = (1 + v)*E
+        rep = generate_standard_repn(e, compute_values=True)
+        self.assertEqual(str(rep.to_expression()), "6")
+        rep = generate_standard_repn(e, compute_values=False)
+        self.assertEqual(str(rep.to_expression()), "(1 + <vtype>)*<vtype>")
+
+    def test_error1(self):
+        class Foo(object):
+            pass
+
+        e = Foo()
+        self.assertRaises(AttributeError, generate_standard_repn, e)
 
 if __name__ == "__main__":
     unittest.main()