Repository: Pyomo/pyomo

Issue:
expression error
I am running a complicated IDAES program written by others that works
with the last release before the expr_dev merge, but does not work
with master as of May 6.  This example may not be very useful for
debugging because it is so complicated and I am not really capable of
figuring out what expression is causing the error.

Here is the final output of the stack dump (the full dump is included below)

  File "/home/woodruff/software/pyomo/pyomo/core/expr/expr_pyomo5.py", line 2544, in _apply_operation
    return self._fcn(result[0])
OverflowError: math range error


I assume that someone else will be bit by this and that someone
might be able to provide a better example for debugging, so I will
keep trying the example. However, this probably needs to be fixed
before the next release, so if it is not fixed by other means then
a few weeks before the next Pyomo release I may need to
bring John Eslick into the loop to help figure out what is not working.
For now, let's just wait.

To reproduce the error:

0. Install idaes
1. cd to ideas/examples/contrib/projects/mea_simple/parameter_estimate
2. make sure there is no directory named pysp_init
3. python mea_estimate_pysp.py

Very quickly you should get

Step 2, Fixed mass and heat flux, Time: ERROR: Constructing component 'cases' from data=None failed: OverflowError:
    math range error

Even when this bug does not bite, it may give errors (but well after
Step 2), so I am including my output here to facilitate verifying
that it is the Pyomo error of interest:

2018-05-06 18:22 - WARNING - idaes.core - _ScalarFlowsheetBlock is a top level flowhseet, but dynamic flag set to "use_parent"value". Dynamic flag set to False by default
2018-05-06 18:22 - WARNING - idaes.core - K10 is a top level flowhseet, but dynamic flag set to "use_parent"value". Dynamic flag set to False by default


----------------------------

Initialize Case: K10 Bed: 1


-------------------------------------------------------
Column initialization, type = Absorber

Step 1, Initialize Properties, Time: 00:00:00.21, Ipopt 3.12.9\x3a Optimal Solution Found
Step 2, Fixed mass and heat flux, Time: ERROR: Constructing component 'cases' from data=None failed: OverflowError:
    math range error
Traceback (most recent call last):
  File "mea_estimate_pysp.py", line 1120, in <module>
    main()
  File "mea_estimate_pysp.py", line 1019, in main
    model.cases = UnitBlock(col_set, rule=rule_case)
  File "/home/woodruff/software/pyomo/pyomo/core/base/block.py", line 538, in __setattr__
    self.add_component(name, val)
  File "/home/woodruff/software/pyomo/pyomo/core/base/block.py", line 978, in add_component
    val.construct(data)
  File "/home/woodruff/software/pyomo/pyomo/core/base/block.py", line 1794, in construct
    self, self._rule, _block, idx, self._options)
  File "/home/woodruff/software/pyomo/pyomo/core/base/misc.py", line 61, in apply_indexed_rule
    return rule(model, index)
  File "mea_estimate_pysp.py", line 1017, in rule_case
    blk.col = generate_case(i)
  File "mea_estimate_pysp.py", line 748, in generate_case
    col_init(blk, case)
  File "mea_estimate_pysp.py", line 535, in col_init
    P = case_data[case]["P"])
  File "mea_estimate_pysp.py", line 494, in col_init2
    col.initialize('default', m_steps=[0.5, 1.0])
  File "/home/woodruff/Documents/Research/IDAES/idaes/idaes/contrib/projects/mea_simple/flowsheet/units/column.py", line 103, in initialize
    self._default_init(*args, **kwargs)
  File "/home/woodruff/Documents/Research/IDAES/idaes/idaes/contrib/projects/mea_simple/flowsheet/units/column.py", line 879, in _default_init
    results = opt.solve(self, tee=stee)
  File "/home/woodruff/software/pyomo/pyomo/opt/base/solvers.py", line 599, in solve
    self._presolve(*args, **kwds)
  File "/home/woodruff/software/pyomo/pyomo/opt/solver/shellcmd.py", line 196, in _presolve
    OptSolver._presolve(self, *args, **kwds)
  File "/home/woodruff/software/pyomo/pyomo/opt/base/solvers.py", line 699, in _presolve
    **kwds)
  File "/home/woodruff/software/pyomo/pyomo/opt/base/solvers.py", line 770, in _convert_problem
    **kwds)
  File "/home/woodruff/software/pyomo/pyomo/opt/base/convert.py", line 110, in convert_problem
    problem_files, symbol_map = converter.apply(*tmp, **tmpkw)
  File "/home/woodruff/software/pyomo/pyomo/solvers/plugins/converter/model.py", line 192, in apply
    io_options=io_options)
  File "/home/woodruff/software/pyomo/pyomo/core/base/block.py", line 1679, in write
    io_options)
  File "/home/woodruff/software/pyomo/pyomo/repn/plugins/ampl/ampl_.py", line 400, in __call__
    include_all_variable_bounds=include_all_variable_bounds)
  File "/home/woodruff/software/pyomo/pyomo/repn/plugins/ampl/ampl_.py", line 979, in _print_model_NL
    quadratic=False)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 387, in generate_standard_repn
    repn=repn)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 937, in _generate_standard_repn
    ans = _collect_sum(expr, 1, idMap, compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 488, in _collect_sum
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 784, in _collect_negation
    return _collect_standard_repn(exp._args_[0], -1*multiplier, idMap, compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 488, in _collect_sum
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 581, in _collect_prod
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 611, in _collect_prod
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 800, in _collect_identity
    return _collect_standard_repn(exp.expr, multiplier, idMap, compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 581, in _collect_prod
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 611, in _collect_prod
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 800, in _collect_identity
    return _collect_standard_repn(exp.expr, multiplier, idMap, compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 920, in _collect_standard_repn
    compute_values, verbose, quadratic)
  File "/home/woodruff/software/pyomo/pyomo/repn/standard_repn.py", line 779, in _collect_nonl
    return Results(constant=multiplier*exp._apply_operation([res.constant]))
  File "/home/woodruff/software/pyomo/pyomo/core/expr/expr_pyomo5.py", line 2544, in _apply_operation
    return self._fcn(result[0])
OverflowError: math range error



Discussion:
@DLWoodruff There's some badness in the expression system happening here.  I'm looking into it.
@DLWoodruff Actually, I cannot find any badness in the expression system.  This is an overflow issue for an exponential term that has a constant argument with a very large value.  It's a large expression, which I'll send to you directly.  I can't see anything wrong with it per se, and I don't know much about the constant values to guess if it's reasonable for the argument to be so large.
@whart222 I just ran Dave's example on master and reproduced the error but when I run on the IDAES branch of Pyomo it runs fine. I tested it on both Python 2.7 and 3.5
@whart222: is this related to #465, which also reports different results after the expr_dev merge?
FYI, I've walked through the expression logic involved with this error, and the calculation appears to be happening normally.  There is a term with something like e^20 in it, and after you multiply this with other terms I can imagine bad things happening.

I suspect that the difference relates to how expressions are generated.  However, that's a black box to me.  I've shared some information on the expressions with Bethany and asked her to help me track down if different expressions are being generated.
Q:  Could this issue be caused by IDAES?  I just noted that the IDAES repos appears to not have been updated to use the new expression API.

But I changed the API intentionally to force errors when this happens.  So I'm not sure.
To my knowledge, the core IDAES framework exercised in this example is not walking or manipulating expressions manually. It is using the existing Pyomo infrastructure to build standard Pyomo components and derived components. There is some complex IDAES infrastructure for parts of the model construction process (ex. properties from a property package) but I can't think of any steps that would conflict with the new expression API. Can you point to a specific examples of this?

(Technically, the IDAES repo is tagged to the IDAES branch of Pyomo and not to master so we shouldn't expect expr_dev API changes to have propagated to the IDAES repos yet)
@whart222 I have gotten a little closer to tracking down the exact part of the model that is causing the problem. If you switch to the expr_dev_debug branch of IDAES you’ll have access to a debugging script I put together:

idaes/examples/contrib/projects/mea_simple/parameter_estimate/temp_mea_estimate_pysp.py 

If you run this you’ll end up with a model where I have deactivated all the Constraints except for the one causing the problem. The ‘math range error’ is getting thrown when trying to write the nl file. One theory I have is that the nodes of the expression tree are being visited in a different order (compared to the IDAES Pyomo branch) when writing the nl file which is causing an `exp()` to be evaluated in one case where it might have been short-cutted previously due to multiplication by 0. The strange thing is that I can display the value of the constraint and all the sub Expressions just fine. Is the tree traversed in a special order when writing an nl file compared to computing the value?

Thanks!  I'll take a look.  I think your hypothesis is reasonable, as I saw various 0*(#) expressions in the code.  I'll try to confirm that.
I tracked down the issue.  I'm working on a PR.

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
@@ -694,46 +694,85 @@ def _collect_var(exp, multiplier, idMap, compute_values, verbose, quadratic):
     return ans
 
 def _collect_pow(exp, multiplier, idMap, compute_values, verbose, quadratic):
+    #
+    # Exponent is a numeric value
+    #
     if exp._args_[1].__class__ in native_numeric_types:
-            exponent = exp._args_[1]
+        exponent = exp._args_[1]
+    #
+    # Exponent is not potentially variable
+    #
+    # Compute its value if compute_values==True
+    #
     elif not exp._args_[1].is_potentially_variable():
         if compute_values:
             exponent = value(exp._args_[1])
         else:
             exponent = exp._args_[1]
+    #
+    # Otherwise collect a standard repn
+    #
     else:
         res = _collect_standard_repn(exp._args_[1], 1, idMap, compute_values, verbose, quadratic)
+        #
+        # If the expression is variable, then return a nonlinear expression
+        #
         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):
-            # The exponent is variable, so this is a nonlinear expression
             return Results(nonl=multiplier*exp)
         exponent = res.constant
 
     if exponent.__class__ in native_numeric_types:
+        #
+        # #**0 = 1
+        #
         if exponent == 0:
             return Results(constant=multiplier)
+        #
+        # #**1 = #
+        #
+        # Return the standard repn for arg(0)
+        #
         elif exponent == 1:
             return _collect_standard_repn(exp._args_[0], multiplier, idMap, compute_values, verbose, quadratic)
-        # If the exponent is >= 2, then this is a nonlinear expression
-        elif exponent == 2:
-            if quadratic:
-                # NOTE: We treat a product of linear terms as nonlinear unless quadratic==2
-                res =_collect_standard_repn(exp._args_[0], 1, idMap, compute_values, verbose, quadratic)
-                if not (res.nonl.__class__ in native_numeric_types and res.nonl == 0) or len(res.quadratic) > 0:
-                    return Results(nonl=multiplier*exp)
+        #
+        # Ignore #**2 unless quadratic==True
+        #
+        elif exponent == 2 and quadratic:
+            res =_collect_standard_repn(exp._args_[0], 1, idMap, compute_values, verbose, quadratic)
+            #
+            # If arg(0) is nonlinear, then this is a nonlinear repn
+            #
+            if not (res.nonl.__class__ in native_numeric_types and res.nonl == 0) or len(res.quadratic) > 0:
+                return Results(nonl=multiplier*exp)
+            #
+            # If computing values and no linear terms, then the return a constant repn
+            #
+            elif compute_values and len(res.linear) == 0:
+                return Results(constant=multiplier*res.constant**exponent)
+            #
+            # If there is one linear term, then we compute the quadratic expression for it.
+            #
+            elif len(res.linear) == 1:
+                key, coef = res.linear.popitem()
+                var = idMap[key]
                 ans = Results()
                 if not (res.constant.__class__ in native_numeric_types and res.constant == 0):
                     ans.constant = multiplier*res.constant*res.constant
-                    for key, coef in six.iteritems(res.linear):
-                        ans.linear[key] = 2*multiplier*coef*res.constant
-                for key, coef in six.iteritems(res.linear):
-                    ans.quadratic[key,key] = multiplier*coef
+                    ans.linear[key] = 2*multiplier*coef*res.constant
+                ans.quadratic[key,key] = multiplier*coef*coef
                 return ans
-            elif exp._args_[0].is_fixed():
-                if compute_values:
-                    return Results(constant=multiplier*value(exp._args_[0])**2)
-                else:
-                    return Results(constant=multiplier*exp)
-        
+
+    #
+    # If args(0) is a numeric value or it is fixed, then we have a constant value
+    #
+    if exp._args_[0].__class__ in native_numeric_types or exp._args_[0].is_fixed():
+        if compute_values:
+            return Results(constant=multiplier*value(exp._args_[0])**exponent)
+        else:
+            return Results(constant=multiplier*exp)
+    #
+    # Return a nonlinear expression here
+    #    
     return Results(nonl=multiplier*exp)
 
 def _collect_reciprocal(exp, multiplier, idMap, compute_values, verbose, quadratic):


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
@@ -2919,10 +2919,345 @@ def test_pow2(self):
         self.assertTrue(len(rep.quadratic_vars) == 0)
         self.assertTrue(len(rep.quadratic_coefs) == 0)
         self.assertTrue(rep.nonlinear_expr is None)
+
+    def test_pow3(self):
+        #       ^
+        #      / \
+        #     a   p
+        m = ConcreteModel()
+        m.a = Var(initialize=2)
+        m.p = Param(default=0, mutable=True)
+
+        e = m.a**m.p
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=False)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 1)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        rep = generate_standard_repn(e, compute_values=True, quadratic=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:1 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        m.p.value = 1
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=False)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 1)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        rep = generate_standard_repn(e, compute_values=True, quadratic=False)
+        #
+        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.a):1 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+    def test_pow4(self):
+        #       ^
+        #      / \
+        #     a   b
+        m = ConcreteModel()
+        m.a = Var(initialize=2)
+        m.b = Var(initialize=0)
+        m.a.fixed = True
+        m.b.fixed = True
+
+        e = m.a**m.b
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=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:1 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        rep = generate_standard_repn(e, compute_values=True, quadratic=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:1 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        m.b.fixed = False
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=False)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 1)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+    def test_pow5(self):
+        m = ConcreteModel()
+        m.a = Var(initialize=2)
+        m.b = Var(initialize=2)
+
+        e = sin(m.a)**2
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=True)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 1)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        e = (m.a**2)**2
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=True)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 1)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        e = (m.a+m.b)**2
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=False)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 2)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=True)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 2)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        e = (m.a+3)**2
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=True)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 2 )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertTrue( rep.is_quadratic() )
+        self.assertTrue( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 1)
+        self.assertTrue(len(rep.linear_coefs) == 1)
+        self.assertTrue(len(rep.quadratic_vars) == 1)
+        self.assertTrue(len(rep.quadratic_coefs) == 1)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { None:9, id(m.a):6, (id(m.a),id(m.a)):1}
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        rep = generate_standard_repn(e, compute_values=True, quadratic=True)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), 2 )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertTrue( rep.is_quadratic() )
+        self.assertTrue( rep.is_nonlinear() )
+        #
+        self.assertTrue(len(rep.linear_vars) == 1)
+        self.assertTrue(len(rep.linear_coefs) == 1)
+        self.assertTrue(len(rep.quadratic_vars) == 1)
+        self.assertTrue(len(rep.quadratic_coefs) == 1)
+        self.assertTrue(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 0)
+        baseline = { None:9, id(m.a):6, (id(m.a),id(m.a)):1 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        m.a.fixed = True
+
+        rep = generate_standard_repn(e, compute_values=True, quadratic=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:12 }
+        baseline = { None:25 }
         self.assertEqual(baseline, repn_to_dict(rep))
 
+    def test_pow6(self):
+        m = ConcreteModel()
+        m.a = Var(initialize=2)
+
+        e = m.a**3
+
+        rep = generate_standard_repn(e, compute_values=False, quadratic=False)
+        #
+        self.assertFalse( rep.is_fixed() )
+        self.assertEqual( rep.polynomial_degree(), None )
+        self.assertFalse( rep.is_constant() )
+        self.assertFalse( rep.is_linear() )
+        self.assertFalse( rep.is_quadratic() )
+        self.assertTrue( 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.assertFalse(rep.nonlinear_expr is None)
+        self.assertTrue(len(rep.nonlinear_vars) == 1)
+        baseline = { }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+        m.a.fixed=True
+
+        rep = generate_standard_repn(e, compute_values=True, quadratic=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:8 }
+        self.assertEqual(baseline, repn_to_dict(rep))
+
+
     def test_abs(self):
         #      abs
         #      /