=======================
 coopr.pyomo CHANGELOG
=======================

-------------------------------------------------------------------------------
 2.7
-------------------------------------------------------------------------------

- Under development.

-------------------------------------------------------------------------------
 2.6.2
-------------------------------------------------------------------------------

- Bug fix in the update process for results objects, which is exposed when
  using suffix data.

- Changes in the output generated by the Pyomo script, to make the semantics
  of the timing clearer.

- Various efficiency improvements due to the use of fixed-positional 
  constructors.

- Fixing logic bug in _tighen_bounds method of _VarValue - if a domain
  lb/ub was equal to None and the corresponding variable lb/ub was also
  equal to None, setlb/setub were being called with None. Technically OK,
  but a waste of time.

-------------------------------------------------------------------------------
 2.6.1
-------------------------------------------------------------------------------

- Fixing serious performance error in Var constructor when variable
  bounds are supplied via a function. Due to incorrect indentation, the
  initialization loop was running in O(N2) time, rather than O(N). No
  functional change - just an incredible reduction in run-time for big
  models.

- Bugfix for pickling EqualityExpressions

- Improved tests, diagnostics, and error messages for compound inequality
  expressions.

- A change to avoid the unexpected behavior in #4224. Previously,
  when using --debug a *.lp file would be written. But that mucks with the
  instance representation, which is not good. With this change, a user
  will need to explicitly dump a model using pyomo2lp (or pyomo2nl).

- Resolving issues with #4225. As part of this change, results are always
  loaded into the model.

- Fixes for #4226. Apparently if a value is returned by a command-line
  entry point ... it then gets printed! (?)

-------------------------------------------------------------------------------
 2.6
-------------------------------------------------------------------------------

- Migrating to the use of entry points instead of explicit script installation.
  This allows for installation and localization of scripts on MS Windows.

- Fixing the symbol_map generated for LP files. This uses '[]' symbols
  rather than '()'.

- Adding formal support for in-place operators (+=, -=, *=, /=,
  **=) for NumericValue? and expressions. This resolves a significant
  performance degradation observed for engval1 and hagar2 CUTE tests
  caused by the addition of "proper" expression cloning in r3798.

- inequalities can now be specified in "compound" form (lb <= expr <= ub)
  - this goes a long way toward resolving #4150
  - there are still several edge cases where this does not work, and 
    some additional error traps and unit tests are still needed. 

- overhaul of Expression unit testing
  - moving several test suites that were not related to unit testing 
    expressions out to other test_*.py files (e.g. param, con, obj). 

- _VarBase and _ParamBase now better approximate the NumericValue? API 
  (in particular, support as_numeric(), is_expression(), and is_relational()) 

- Adding a method to update the data in a results object
  to use (a) labels from the model and (b) variable IDs from the
  model.

- Changed the LP writer to write the true name of the objective.

- Misc bug fixes in NL writer.

- Adding a hook to see if the initialization function for a set 
  has a 'dimen' attribute.

- Overhaul of Constraint generation code
  - collapsing _LessThanExpression and _LesThanOrEqualExpression to a
    single _InequalityExpression that can hold 2 or 3 arguments
  - centralizing relational expression generation in
    expr.generate_relational_expression()
  - standardizing tests in constraint.add() to be more robust to
    unexpected input - slight performance improvement in constraint.add()

- Rework of expressions to perform a lazy cloning of expression subexpressions.
  This resolves bugs that a variety of users have reported.

- Improved error detection of constraints with non-finite bounds.

- Adding regression test for Pyomo benders example using CPLEX

- Adding a future import for integer division in various places,
  to resolve issues with integer data...

- Various updates to the pyomo command line:
  - Added a -c/--catch-exceptions option, which generates an error
    when exceptions are generated. The -d/--debug option does the same thing,
    but it generates lots of output!

- Rework of the pyomo command line to create a concise output

- Many efficiency improvements:
  - Preprocessing
  - Expression generation
  - Using Python slots logic to store data more efficiently
  - Replaced the product set iterator with itertools iterator
  - Automatic disabling of garbage collection during model generation
  - Eliminated expression verify() logic
  - Various loop optimizations
  - Eliminated the some preprocessing steps

- Many improvements to diagnostic output and error handling.  This includes the
  use of Python's logging utility, and the addition of options to
  the pyomo command line to control logging output.

- Fix to variable reset() logic.  After calling reset(), variable values will
  be None unless an initialization value is provide.

- Added a higher performance variation of the p-median example.

- Deprecating the use of 'Model' as the base abstract Model class.

- Setup various call-back functions that can be executed by the
  pyomo command line

- Added options to manage memory profiling

- Introduced a parameter representation class that allows for a more 
  robust experience using Param() objects with non-Pyomo data. Two
  parameter representations are supported:
  - pyomo_dict This is the default, and it supports data in ParamValue objects.
  - sparse_dict Use a class that looks like a sparse dictionary.

- Extended API of NumericValue objects so expressions like "model.p > 1" 
  can be used in conditionals.

-------------------------------------------------------------------------------
 2.5
-------------------------------------------------------------------------------

- Some progress toward functional indexed Piecewise components.

- Adding example of Piecewise construct using breakpoint and slope rules,
  as opposed to explicit/direct lists.

- Adding omitted pprint() method for SOS constraints.

- Fixing diagnostic error message when attempting to solve quadratic
  programs with GLPK - code for generating message was not syntatically
  legal.

- Interim fixes to output of quadratic terms in LP writer - more to do,
  but at least the basic examples now work.

- Migrated OS-specific functionality into coopr.os.

- Supressing a validation test with NumericConstant. If the user specifies
  a value, we are (now) assuming it is actually a numeric value - otherwise,
  the domain check significantly inflates the run-time associated with
  expression tree creation. This needs to be revisited in the Coopr
  2.5 re-write.

- Added a simple knapsack example to illustrate the difference between
  a concrete and abstract model.

- Fixing bugs in has_discrete_variables() method of PyomoModel.

- Eliminating initial domain check when constructing numeric constants
  and the default domain (Reals) is specified.

-------------------------------------------------------------------------------
 2.4
-------------------------------------------------------------------------------

- Fixing bug in ord() method of sets.

- Extending semantics of Pyomo scripting to recognize plugins that can
  be used to customize the Pyomo script behavior (e.g.  print results,
  save model instances, etc.)

- Misc changes that attempt to be more careful in how files are opened
  and closed. MS Windows is particularly sensitive about removing files
  that are currently open.

- Rework of tests to use new plugin factory mechanism
  supported by pyutilib.component.core

- Some performance improvements in identify_vars.py, obtained by
  significantly reducing the number of times that the type query (e.g.,
  is_binary, isinstance) methods of variables are called.

- Introduced the ConcreteModel and AbstractModel classes, to clearly denote
  the type of model that the Pyomo user is defining.

- Adding debug output to report when each variable is constructed, as with
  parameters, sets, constraints, and objectives. 

- Allow the same value is added to a set twice. This
  shouldn't cause an error.

- Added a "noruleinit" keyword option to the Constraint and Objective
  classes.  If specified, then the following hold: (1) the user is
  explicitly taking responsibility for constructing individual index
  elements for instances of these classes.  (2) no warning will be output
  if no "rule" or "expr" keywords are specified in the constructors of
  these classes.  This change was motivated by the silence of pyomo if
  no rule is specified in a constraint constructor, making model error
  diagnostics more difficult than they need be. If no rule is specified
  and the noruleinit keyword is absent, then Pyomo will output a warning
  message indicating the situation.

- Adding a warning in cases where users specify both the rule and
  noinitrule keywords in the Constraint and Objective class
  constructors. If a rule is specified, it will be used.

- Added more useful error messages for a variety of contexts of modeling errors.

- Changed error checking logic for all derived classes of Component.
  Before, IndexedComponent would perform error checking to ensure that
  a ctype was being passed to the Component constructor. Now that error
  checking occurs in Component; this is to allow classes to derive from
  Component without also deriving from IndexedComponent.

- Added new abstract base class ConstraintBase.  ConstraintBase will
  serve as a base class for all constraint-like objects.  Currently only
  Constraint exists; however, this change is in preparation for SOS1,
  SOS2, and SOS-n constraint classes, among others.

- Changes to coopr.pyomo to support SOS constraints.

- Changed default behavior of SOSConstraint.  SOSConstraint used to
  assign a default value of '1' to the 'sos' or 'level' keywords if none
  were provided by the user. It now raises a TypeError asking the user to
  specify the value.

- Adds Piecewise variables.  Piecewise objects are variables that are
  constrained to have a value determined by a piecewise linear
  function. If the piecewise linear function is concave or convex, the
  variable is constrained by a number of lienar constraints. If it is
  nonconvex, then it is comstrained using SOS2 sets.

- Updates to the pyomo command line:
  - Added '-i' option to drop the user to an interactive shell when
    an error occurs.
  - Alphabetized options and split into logical groups.

- Reformated output of LP files to support a maximum line-length (510
  characters).

- Added support for generalized sums over k sets (like in AMPL)
  The multisum function can be used to support a summation such as:
    sum(model.A[i,j,k] for (i,j,k) in multisum(setI, setJ, setK))

- Updates to allow indexed variables to contain both
  continuous and discrete variables. This is accomplished by allowing
  the 'within' and 'domain' keywords to accept a rule that return the
  set each variable should be a part of. These changes should be mostly
  transparent to the user unless they seek out this functionality.

- Adding EqualityTransform, which creates an equivalent form of a model
  by replacing inequality constraints with equality constraints and
  slack and excess variables.

- Added a class heirarchy for model transformations: non/linear,
  abstract/concrete, non/isomorphic.  Note that each group encompasses
  all possible transformations; specifically, every transformation is
  either linear or not linear, abstract or not abstract, and isomorphic
  or not isomorphic. Derived transformations are designed to multiply
  inherit. Failing to inherit from one group shows indifference to
  that group.

- Adding a Block component, which is a base class for Model.  Note that
  this is a preliminary implementation. I haven't added added logic
  for recursing through subblocks.  To retain backwards compatibility,
  we don't need that functionality.

- Added nonlinear support to pyomo. This includes new intrinsic functions and
  new NL writer as well as corresponding tests.

- Changed semantics of Python operators.  Now, new expressions are returned 
  when an operator is applied, rather than editing one of the operators in
  place.

- Resolved various Pyomo data file parse errors

- Added support for ODBC data imports.  This includes support using the pyodbc
  python package (if it's installed).  

- Allow Pyomo components to automatically find rules with corresponding names:

  def c_rule(model):
    return model.x
  model.c = Constraint()

- Adding support for non-mutable parameters, which are now
  the default. These are simply parameters that are stored as
  dictionaries with float values rather than ParamValue? values.

- Adding logic to allow ASL solverss to be specified as:

    --solver=asl:PICO

- Rework to set the sys.path environment to find the PLY parser tables. 
  This should allow the parse table to be written only once.

- Various performance-related enhancements that rework the internals of
  numeric values and constants.

- Adding logic for LP writer when dealing with linearized expressions
  involving fixed variables. 

- Added "has_discrete_variables" method to PyomoModel?, to support query
  by MIP plugins - which often need this method to determine the type
  of solution information (e.g., duals) to extract.

- Added a "nochecking" keyword argument to Params. Intended strictly
  for use by algorithm developers, it by-passes the call to
  _valid_indexed_component, which was taking a huge amount of time in
  various PySP algorithms. Use sparingly and judiciously! May also apply
  in the near future to other aspects of setitem.

-------------------------------------------------------------------------------
 2.3
-------------------------------------------------------------------------------

- Misc rework of the scripting modules. These changes allow this
  functionality to be used more effectively within other Python scripts.

- Added the 'include' command, which can include other *.dat files. This
  works like the AMPL include command, with the exception that it must
  be terminated by a semicolon.

- Reworked the AMPL datafile plugin to simple execute an include command
  on a *.dat file. This rework has the advantage that filename/lineno
  information is now propigated throught he AMPL command processing.

- Reworked the parsing of data command files (formerly known
  as AMPL DAT files). This rework is the first step towards a full
  parse of these files. I've used PLY to lex/yacc these files. This
  should resolve a variety of issues that we've observed relating to the
  sensitivity of the old parser to whitespace. 

- Added an 'import' command to integrate data from external sources 
  (plain text, csv, spreadsheets, etc)

- Added suffix option to pyomo script, to enable specification of
  suffixes on the command-line.

- Renaming the 'presolve' phase in Pyomo to 'preprocess'. We'll
  eventually want an explicit presolve phase, but that will be applied
  as a transformation, right before the problem is written and sent to
  the solver. Currently, this preprocess phase collects data about the
  model and computes the canonical representations for expressions.

- Created the ability to support the construction of concrete models.
  The concrete_mode() method for Model objects enables this mode.
  When in the concrete mode, each component added to the model has
  its construct() method called immediately after the component is
  added to the model. The symbolic_mode() method for Model objects
  can be called to switch back to a symbolic mode (which defers the
  execution of construct().

  Bad things might happen if you switch back and forth between these
  modes. Notably, if you ever generate components in symbolic mode,
  then you need to switch back to symbolic mode before calling create().

  Note that the Model.create() method is still called when the model
  construction is 'done', even when done completely in concrete mode.
  This basically calls the preprocessing steps, and this method returns
  the current model (i.e. no cloning is done when building a concrete
  model).

- Enhanced the API for ordered sets.

- Misc portability fixes.

- Significantly improved performance of PyomoModel? _clear_attribute
  method, mainly by eliminate unnecessary calls to it through setattr_exec

- Fixed issue with LP format writer involving the failure to output model
  prefixes for the constant-offset term. Only impacts the PySP EF writer -
  eliminates a warning from CPLEX, and an error report from GLPK.

- Extended the Pyomo parser to allow for the specification of namespaces 
  in data command files.

- Bug fix: recognize when bounds are constant expressions, and
  print their value.

-------------------------------------------------------------------------------
 2.2
-------------------------------------------------------------------------------

- Reworked the ModelData logic to use plugins to load data from different
  sources.

- Reworked the canonical expression definition to include a dictionary
  from variable ID -> _VarValue

- Added ability to process multiple *.dat files on the Pyomo command line

- Suppressed warning for 'constrant constraint' when writing LP files.

- A rework of the NL/LP file writers. This now uses the
  canonical expression representation. 

- Allowed PyomoModel to load results with 'Warning' status

- Cut the runtime of the PyomoModel._load_solution method by 2/3.

- Added pyomo2lp and pyomo2nl commands.

- Refactored the pyomo command-line script to make it easier to write 
  related scripts.

- Setup a draft implementation of expressions for intrinsic functions.

- Changed the setitem interface for the parameter and variable base class 
  to allow invocations of the following form:

    var[None] = some_value

  In cases where the variable Var is a singleton, i.e., non-indexed. This slight
  abuse of syntax is extremely useful in PH (and anywhere else where we have
  automated manipulation of variable values), as it avoids various if-then statements.

- Adding the @set_options decorator, which can be used
  to specify options for temporary sets that are defined by
  index functions.

- Added methods to clear objective/constraint data.

- Changes to make the API for Model() functions/attributes by
  1-based indexing. This wound up having very little impact on the
  Pyomo code base, though it has a bigger impact on my implementation of the FDT
  heuristic.

- Added xsequence(), which mimics xrange().

- Allow expressions to be generated from a dictionary variable-id ->
  _VarValue  

- Added fix to update Model statistics after a transformation.

- Adding a sequence() function, which is analogous to range()
  for generating 1-indexed sequences.

-------------------------------------------------------------------------------
 2.1
-------------------------------------------------------------------------------

- Removed some TBD notes in the Benders example, and checked in the full
  benders script (a debug version was committed initially, that only
  dealt with iteration 1). This version replicates, to within precision,
  the AMPL execution. Should terminate in 5 master iterations.

- Misc rework of variable presolving. Now, model statistics are
  stored in a more obvious location, and using more verbose names.

- Added functions that can (1) extract a canonical representation
  from an expressions, and (2) generate an expression from a canonical
  representation.

- Adding ability to load a list or tuple of values into a Pyomo
  model. These are loaded into the variables in the order in which the
  variables are identified.

- Updated variable naming. Special symbols are mapped to
  a name that contains _Q#_, where # the ASCII decimal representation
  for that symbol.

- Added support for denoting constraint inequalities as 'strict'. Added
  tests to verify that strict inequalities are recognized.

- Resolved #3970. When a parameter is specified with a default
  value, we should be able to refer to its index set directly, since
  all values are tacitly defined.

- Added a 'random' solver for the p-median example.

- Added ".solver-mipgap" option to the pyomo script, mirroring recent useful
  updates to the PH script.

- Simplified the syntax for adding a constraint to a Constraint object.

- Reworking how components interact with models. Now, components can
  only be initialized using data from the model that they are associated
  with.  Thus, models and components are tightly coupled. This allows
  the following syntax:

    model.x = Param(model.A)
    model.construct()

  The construction process uses the model data that is associated with
  the parameter. Also, this commmit allows models to be components of
  another model:

    m1=Model()
    m2=Model()
    m2.m1 = m1

  Note, however, that model construct is required to be done
  separately. When model m2 is constructed, the m1 component is not
  constructed.

- Added check to avoid printing an objective with an empty linear sum.

- Rework of the amplbook2 examples, and other Pyomo examples.

- A change in semantics for setting up dimen and dim. This change requires
  that users specify dimen in situtations where it is not obvious from the
  component declaration. For example, if you initialize from a function,
  then you'll need to specify dimen if the function returns n-tuples.

- Added an extension point for plugins that suport model transformations.
  Two transformations have been defined:  a transformation for eliminating
  fixed variables, and a transformation for relaxing integrality.  These 
  can be generically accessed with the apply_transformation() function.

- Extended API of the PyomoModel class to add a variety of helper
  functions (e.g. accessing constraints, variables and objectives).
  Adding a method for getting the model solution, as a vector.

- Added tests to exercise the Pyomo command-line.

- Updates to Pyomo command-line options:

  Added --model-name option, which allows the specification of an object
  other than 'model' for the model that is optimized.

  Added support for create_model(), which accepts a dictionary or
  pyutilib.misc.Container object containing the options specified with the
  --model-options option. This function returns a model that is optimized.

  Added the 'errors' debugging mode. When specified, exceptions dump
  a traceback. Otherwise, exceptions are caught and only the exception
  string is printed.

- Adding support for component index deactivation.  This supports the
  following semantics:

    model.C = Constraint(model.A)
    model.C[index].deactivate()

  Note that the current implementation requires the user to query whether
  each index is active:

    if model.C[index].active:
        # Do something

  I could have alternatively changed the iterator for the constraint,
  but then that could mask the existence of a constraint, making it
  difficult to reactivate.

  Finally, note that this activation mechanism is independent
  of the component level activation/deactivation:

    model.C.deactivate()
    # All C constraints are deactivated
    model.C[index].deactivate
    # You can still manipulate the C constraint
    model.C.activate()
    # Now, the C constraint is active, except for the '
    # 'index' constraint

- A rework of component management in Pyomo.  Component types are now
  managed with the natural class types (e.g.  Var for variables, rather
  than _VarBase). Further, the components should now be accessed with
  model methods: components() or active_components().  For example,

    model.components(Var)

  returns a dictionary of the Var components.

- Created the ComponentBase class, which manages the initialization of
  components. This consolidates the mechanism needed to generalize
  the component indexing operations.

- Reworking SetArray constructor to create temporary set objects for non-set
  index arguments. These arguments are passed into a Set object
  with the 'initialize' argument.

- Extended the constraint generation logic to evaluate whether the
  constraint expression contains constant values. This extension allows
  the following types of constraints to be specified:

    def f(model)
        return 0 < model.x

    def g(model)
        return model.x == model.y

    def h(model)
        return model.y > model.z

  However, it's pretty clear now that the following cannot be supported in
  Python:

    def j(model)
        return 0 < model.x < 1

  To add upper and lower bounds, a user will need to return a tuple value:

    def j(model)
        return (0, model.x, 1)

  or return an expression that is generated incrementally:

    def j(model)
        e = 0 < model.x
        return e < 1

- Significantly changed - and improved - the handling of variable lower
  and upper bounds.  In the old version of pyomo, if parameters were
  supplied as bounds, the lb/ub were silently ignored when writing
  LP/NL/etc files.

  In the new version of pyomo, these parameters are stored and handled
  to avoid this issue. In particular, the "lb" and "ub" attributes
  of a variable are either (1) None, (2) a NumericConstant?, or (3) a
  _ParamBase. The latter two objects share the common () operator. Thus,
  to access the lb and ub attributes of a variable, one should either
  test for None, or use lb() or ub() to extract the value.

- Added constraint symbol maps when writing NL files, so the constraint names
  can be mapped back (e.g., when dealing with dual variables in SOL files)
  into the user-recognized names.

-------------------------------------------------------------------------------
 2.0
-------------------------------------------------------------------------------

- Initial release of Coopr to create the coopr.pyomo package.

- See coopr.dist for previous ChangeLog information related to Coopr.

