def pyomo4_generate_canonical_repn(exp, idMap=None, compute_values=True): if exp is None: return CompiledLinearCanonicalRepn() if exp.__class__ in native_numeric_types: ans = CompiledLinearCanonicalRepn() ans.constant = value(exp) return ans if not exp.is_expression(): if exp.is_fixed(): ans = CompiledLinearCanonicalRepn() ans.constant = value(exp) return ans elif isinstance(exp, _VarData): ans = CompiledLinearCanonicalRepn() ans.constant = 0 ans.linear = (1., ) ans.variables = (exp, ) return ans else: raise RuntimeError("Unrecognized expression node: %s" % (type(exp), )) degree = exp.polynomial_degree() if degree == 1: _stack = [] _args = exp._args _idx = 0 _len = len(_args) _result = None while 1: # Linear expressions just need to be filteres and copied if exp.__class__ is expr_pyomo4._LinearExpression: _result = expr_pyomo4._LinearExpression(None, 0) _result._args = [] _result._coef.clear() _result._const = value(exp._const) for v in _args: _id = id(v) if v.is_fixed(): _result._const += v.value * value(exp._coef[_id]) else: _result._args.append(v) _result._coef[_id] = value(exp._coef[_id]) _idx = _len # Other expressions get their arguments parsed one at a time if _idx < _len: _stack.append((exp, _args, _idx + 1, _len, _result)) exp = _args[_idx] if exp.__class__ in native_numeric_types: _len = _idx = 0 _result = exp elif exp.is_expression(): _args = exp._args _idx = 0 _len = len(_args) _result = None continue elif isinstance(exp, _VarData): _len = _idx = 0 if exp.is_fixed(): _result = exp.value else: _result = expr_pyomo4._LinearExpression(exp, 1.) else: raise RuntimeError("Unrecognized expression node: %s" % (type(exp), )) # # End of _args... time to move up the stack # # Top of the stack. _result had better be a _LinearExpression if not _stack: ans = CompiledLinearCanonicalRepn() # old format ans.constant = _result._const ans.linear = [] for v in _result._args: # Note: this also filters out the bogus NONE we added above _coef = _result._coef[id(v)] if _coef: ans.variables.append(v) ans.linear.append(_coef) if idMap: if None not in idMap: idMap[None] = {} _test = idMap[None] _key = len(idMap) - 1 for v in ans.variables: if id(v) not in _test: _test[id(v)] = _key idMap[_key] = v _key += 1 return ans # Ok ... process the new argument to the node. Note that # _idx is 1-based now... _inner_result = _result exp, _args, _idx, _len, _result = _stack.pop() if exp.__class__ is expr_pyomo4._SumExpression: if _idx == 1: _result = _inner_result else: _result += _inner_result elif exp.__class__ is expr_pyomo4._ProductExpression: if _idx == 1: _result = _inner_result else: _result *= _inner_result elif exp.__class__ is expr_pyomo4._DivisionExpression: if _idx == 1: _result = _inner_result else: _result /= _inner_result elif exp.__class__ is expr_pyomo4._NegationExpression: _result = -_inner_result elif exp.__class__ is expr_pyomo4._PowExpression: # We know this is either constant or linear if _idx == 1: _result = _inner_result else: coef = value(_inner_result) if not coef: _result = 1. elif coef != 1: _result = _result**coef elif exp.__class__ is expr_pyomo4.Expr_if: if _idx == 1: _result = [_inner_result] else: _result.append(_inner_result) if _idx == 3: if value(_result[0]): _result = _result[1] else: _result = _result[2] elif exp.__class__ in _identity_collectors: _result = _inner_result elif exp.is_fixed(): _result = value(exp) else: raise RuntimeError("Unknown non-fixed subexpression type %s" % (type(exp), )) elif degree == 0: ans = CompiledLinearCanonicalRepn() ans.constant = value(exp) return ans # **Py3k: degree > 1 comparision will error if degree is None elif degree and degree > 1: raise RuntimeError( "generate_canonical_repn does not support nonlinear Pyomo4 expressions" ) ans = collect_general_canonical_repn(exp, idMap, compute_values) if 1 in ans: linear_terms = {} for key, coef in iteritems(ans[1]): linear_terms[list(key.keys())[0]] = coef ans[1] = linear_terms return GeneralCanonicalRepn(ans) else: return GeneralCanonicalRepn({ None: exp, -1: collect_variables(exp, idMap) })
def pyomo4_generate_canonical_repn(exp, idMap=None, compute_values=True): if exp is None: return CompiledLinearCanonicalRepn() if exp.__class__ in native_numeric_types: ans = CompiledLinearCanonicalRepn() ans.constant = value(exp) return ans if not exp.is_expression(): if exp.is_fixed(): ans = CompiledLinearCanonicalRepn() ans.constant = value(exp) return ans elif isinstance(exp, _VarData): ans = CompiledLinearCanonicalRepn() ans.constant = 0 ans.linear = (1.,) ans.variables = (exp,) return ans else: raise RuntimeError( "Unrecognized expression node: %s" % (type(exp),) ) degree = exp.polynomial_degree() if degree == 1: _stack = [] _args = exp._args _idx = 0 _len = len(_args) _result = None while 1: # Linear expressions just need to be filteres and copied if exp.__class__ is expr_pyomo4._LinearExpression: _result = expr_pyomo4._LinearExpression(None, 0) _result._args = [] _result._coef.clear() _result._const = value(exp._const) for v in _args: _id = id(v) if v.is_fixed(): _result._const += v.value * value(exp._coef[_id]) else: _result._args.append(v) _result._coef[_id] = value(exp._coef[_id]) _idx = _len # Other expressions get their arguments parsed one at a time if _idx < _len: _stack.append((exp, _args, _idx+1, _len, _result)) exp = _args[_idx] if exp.__class__ in native_numeric_types: _len = _idx = 0 _result = exp elif exp.is_expression(): _args = exp._args _idx = 0 _len = len(_args) _result = None continue elif isinstance(exp, _VarData): _len = _idx = 0 if exp.is_fixed(): _result = exp.value else: _result = expr_pyomo4._LinearExpression(exp, 1.) else: raise RuntimeError( "Unrecognized expression node: %s" % (type(exp),) ) # # End of _args... time to move up the stack # # Top of the stack. _result had better be a _LinearExpression if not _stack: ans = CompiledLinearCanonicalRepn() # old format ans.constant = _result._const ans.linear = [] for v in _result._args: # Note: this also filters out the bogus NONE we added above _coef = _result._coef[id(v)] if _coef: ans.variables.append(v) ans.linear.append(_coef) if idMap: if None not in idMap: idMap[None] = {} _test = idMap[None] _key = len(idMap) - 1 for v in ans.variables: if id(v) not in _test: _test[id(v)] = _key idMap[_key] = v _key += 1 return ans # Ok ... process the new argument to the node. Note that # _idx is 1-based now... _inner_result = _result exp, _args, _idx, _len, _result = _stack.pop() if exp.__class__ is expr_pyomo4._SumExpression: if _idx == 1: _result = _inner_result else: _result += _inner_result elif exp.__class__ is expr_pyomo4._ProductExpression: if _idx == 1: _result = _inner_result else: _result *= _inner_result elif exp.__class__ is expr_pyomo4._DivisionExpression: if _idx == 1: _result = _inner_result else: _result /= _inner_result elif exp.__class__ is expr_pyomo4._NegationExpression: _result = -_inner_result elif exp.__class__ is expr_pyomo4._PowExpression: # We know this is either constant or linear if _idx == 1: _result = _inner_result else: coef = value(_inner_result) if not coef: _result = 1. elif coef != 1: _result = _result ** coef elif exp.__class__ is expr_pyomo4.Expr_if: if _idx == 1: _result = [_inner_result] else: _result.append(_inner_result) if _idx == 3: if value(_result[0]): _result = _result[1] else: _result = _result[2] elif exp.__class__ in _identity_collectors: _result = _inner_result elif exp.is_fixed(): _result = value(exp) else: raise RuntimeError( "Unknown non-fixed subexpression type %s" % (type(exp),) ) elif degree == 0: ans = CompiledLinearCanonicalRepn() ans.constant = value(exp) return ans # **Py3k: degree > 1 comparision will error if degree is None elif degree and degree > 1: raise RuntimeError("generate_canonical_repn does not support nonlinear Pyomo4 expressions") ans = collect_general_canonical_repn(exp, idMap, compute_values) if 1 in ans: linear_terms = {} for key, coef in iteritems(ans[1]): linear_terms[list(key.keys())[0]] = coef ans[1] = linear_terms return GeneralCanonicalRepn(ans) else: return GeneralCanonicalRepn( { None: exp, -1 : collect_variables(exp, idMap) } )