//==================================================================================================
// L i n e a r _ s y s t e m                                                              Interface
// S t r u c t u r e
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module defines the structure of a linear program. What we reference here as a linear
   system is in fact a linear program (it has a linear objective function). */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "linear_system/structure.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guLinearSystemStructure
#define guLinearSystemStructure

// Headers //---------------------------------------------------------------------------------------
#include <algorithm> /*INCLUDE*/
#include <bpp/standard.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef LINEAR_SYSTEM_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  linearSystemStructure
#define private_area linearSystemStructure_private

namespace public_area  { /*NAMESPACE*/ using namespace standard; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniLinearSystemStructure
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <class prContent> class clConstraint;
 template <class prContent> class clLinearSystem;
 template <class prContent> class clObjective;
 template <class prContent> class clVariable;
 //-----------------------------------------------------------------------------------Variable Types
 /*TYPE*/ /* Key identifying a variable in a linear system. */
 typedef tyCardinal tyVariableKey;

 /*TYPE*/ /* Kind of constraint of a linear system. */
 enumeration { equality, inferiority, superiority } tyConstraintKind;

 /*TYPE*/ /* Kind of objective of a linear system. */
 enumeration { minimum, maximum } tyOptimum;

 /*TYPE*/ /* Kind of variable of a linear system. */
 enumeration { realVariable, integralVariable } tyVariableKind;

 /*TYPE*/ /* List of coefficients, each associated with a variable of a linear system. */
 typedef std_map(tyVariableKey,tyReal) clCoefficientX;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const tyVariableKey    tcVariableKey;
 typedef const clCoefficientX   ctCoefficientX;
 typedef const tyConstraintKind tcConstraintKind;
 typedef const tyOptimum        tcOptimum;
 typedef const tyVariableKind   tcVariableKind;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {
 template <class prContent>
 clOutStream & operator << (clOutStream &,const clConstraint<prContent> &);

 template <class prContent>
 clOutStream & operator << (clOutStream &,const clObjective<prContent> &);

 template <class prContent>
 clOutStream & operator << (clOutStream &,const clLinearSystem<prContent> &);

 template <class prContent>
 clOutStream & operator << (clOutStream &,const clVariable<prContent> &);

 template <class prContent> clInStream & operator >> (clInStream &,clLinearSystem<prContent> &);

 function tyConstraintKind constraintKind(ctString &);
 function tyOptimum        optimum(ctString &);
 function tyVariableKind   variableKind(ctString &);

 inline clString constraintKindToString(tyConstraintKind);
 inline clString optimumToString(tyOptimum);
 inline clString variableKindToString(tyVariableKind);
}

namespace private_area { testing_mode ( function void test(void); ) }

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erIncompatibleConstraints;
 /* The two constraints are incompatible (not the same number of coefficients). */

 /*ERROR*/ extern_error erIncompatibleObjectives;
 /* The two objectives are incompatible (not the same number of coefficients). */

 /*ERROR*/ extern_error erInconsistentConstraintStructure;
 /* The structure of the constraint is inconsistent. */

 /*ERROR*/ extern_error erInvalidConstraintKindString;
 /* The contraint kind specified is not valid. */

 /*ERROR*/ extern_error erInvalidConstraintNumber; /* The constraint number is not valid. */

 /*ERROR*/ extern_error erInvalidOptimumString;
 /* The string does not represent an objective kind. */

 /*ERROR*/ extern_error erInvalidVariableKindString;
 /* The string does not represent a variable kind. */

 /*ERROR*/ extern_error erInvalidVariableKey; /* The variable key is not valid. */
 /*ERROR*/ extern_error erVariableKeyAlreadyExists; /* The variable key already exists. */
}

// Constants & Variables //-------------------------------------------------------------------------
extern_static_constant(private,tcString,goConstraintsEndFlag,?);
extern_static_constant(private,tcString,goConstraintsStartFlag,?);
extern_static_constant(private,tcString,goConstraintFlag,?);
extern_static_constant(private,tcString,goLinearSystemEndFlag,?);
extern_static_constant(private,tcString,goLinearSystemStartFlag,?);
extern_static_constant(private,tcString,goNegativeInfinityFlag,?);
extern_static_constant(private,tcString,goNullFlag,?);
extern_static_constant(private,tcString,goObjectiveFlag,?);
extern_static_constant(private,tcString,goPositiveInfinityFlag,?);
extern_static_constant(private,tcString,goSolvedFlag,?);
extern_static_constant(private,tcString,goUnsolvedValueFlag,?);
extern_static_constant(private,tcString,goVariablesEndFlag,?);
extern_static_constant(private,tcString,goVariablesStartFlag,?);
extern_static_constant(private,tcString,goVariableFlag,?);

// C o n s t r a i n t  Interface //----------------------------------------------------------------
namespace public_area {
 /*CLASS clConstraint */
 /* Represents a constraint of a linear system. The parameter of the template is the type of data
    the variables of the linear system carry. */
 template <class prContent> class clConstraint {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clConstraint */ /* This class. */
  public_property typedef clConstraint<prContent> cpConstraint;

  /*TYPE clConstraint */ /* Type of linear system the constraint belongs to. */
  public_property typedef clLinearSystem<prContent> cpLinearSystem;

  /*TYPE clConstraint */ /* Type of objective the constraint is associated with. */
  public_property typedef clObjective<prContent> cpObjective;

  /*TYPE clConstraint */ /* Type of variable the constraint is associated with. */
  public_property typedef clVariable<prContent> cpVariable;

  /*TYPE clConstraint */ /* List of constraints. */
  public_property typedef std_vector(cpConstraint *) cpConstraintS;

  /*TYPE clConstraint */ /* List of variables. */
  public_property typedef std_map(tyVariableKey,cpVariable *) cpVariableX;
  //-----------------------------------------------------------------------------------------Friends
  friend class clVariable<prContent>;
  //-----------------------------------------------------------------------------------------Private
  private_property cpLinearSystem & atLinearSystem;

  private_property constructor clConstraint(const clConstraint &);
  private_property tyReal value(void) const;
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clConstraint */ /* Mark used by some algorithms. */
  read_write_attribute(tyMark,atMark,mark);

  /*ATTRIBUTE clConstraint */ /* Coefficients of the constraint. */
  read_only_attribute(clCoefficientX,atCoefficientX,coefficients);

  /*ATTRIBUTE clConstraint */ /* Boundary of the constraint. */
  read_write_attribute(tyReal,atBoundary,boundary);

  /*ATTRIBUTE clConstraint */ /* Kind of the constraint. */
  read_write_attribute(tyConstraintKind,atKind,kind);

  public_property const cpLinearSystem & linearSystem(void) const;

  public_property constructor clConstraint(cpLinearSystem &,const cpConstraint &);
  public_property constructor clConstraint(cpLinearSystem &,tyConstraintKind=equality);
  public_property constructor clConstraint(cpLinearSystem &,clInStream &);
  public_property destructor  clConstraint(void);

  public_property cpConstraint & operator = (const cpConstraint &);
  public_property tyReal         operator [] (tyVariableKey) const;

  public_property tyReal    coefficient(tyVariableKey) const;
  public_property tyBoolean isActive(tyReal=epsilon()) const;
  public_property tyBoolean isViolated(tyReal=epsilon()) const;
  public_property void      setCoefficient(tyVariableKey,tyReal);
 };
}

// L i n e a r S y s t e m  Interface //------------------------------------------------------------
namespace public_area {
 /*CLASS clLinearSystem */
 /* Represents a linear system. The parameter of the template is the type of data the variables
    carry. */
 template <class prContent> class clLinearSystem {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clLinearSystem */ /* Type of constraints the linear system contains. */
  public_property typedef clConstraint<prContent> cpConstraint;

  /*TYPE clLinearSystem */ /* This class. */
  public_property typedef clLinearSystem<prContent> cpLinearSystem;

  /*TYPE clLinearSystem */ /* Type of objective the linear system contains. */
  public_property typedef clObjective<prContent> cpObjective;

  /*TYPE clLinearSystem */ /* Type of variable the linear system contains. */
  public_property typedef clVariable<prContent> cpVariable;

  /*TYPE clLinearSystem */ /* List of constraints. */
  public_property typedef std_vector(cpConstraint *) cpConstraintS;

  /*TYPE clLinearSystem */ /* List of variables. */
  public_property typedef std_map(tyVariableKey,cpVariable *) cpVariableX;
  //-----------------------------------------------------------------------------------------Friends
  friend class clConstraint<prContent>;
  friend class clObjective<prContent>;
  friend class clVariable<prContent>;
  //-----------------------------------------------------------------------------------------Private
  private_property cpObjective * atObjective;

  private_property void copy(const clLinearSystem &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clLinearSystem */ /* Indicates if the system is solved. */
  read_write_attribute(tyBoolean,atSolved,solved);

  /*ATTRIBUTE clLinearSystem */ /* Mark used by some algorithms. */
  read_write_attribute(tyMark,atMark,mark);

  /*ATTRIBUTE clLinearSystem */ /* Variables of the system. */
  read_only_attribute(cpVariableX,atVariableX,variables);

  /*ATTRIBUTE clLinearSystem */ /* Constraints of the system. */
  read_only_attribute(cpConstraintS,atConstraintS,constraints);

  public_property constructor clLinearSystem(void);
  public_property constructor clLinearSystem(const cpLinearSystem &);
  public_property destructor  clLinearSystem(void);

  public_property cpLinearSystem &     operator = (const cpLinearSystem &);
  public_property cpConstraint &       operator [] (tyCardinal);
  public_property const cpConstraint & operator [] (tyCardinal) const;

  public_property cpConstraint &       constraint(tyCardinal);
  public_property const cpConstraint & constraint(tyCardinal) const;
  public_property tyVariableKey        getNewVariableKey(tyVariableKey) const;
  public_property tyVariableKey        getNewVariableKey(void) const;
  public_property cpObjective &        objective(void);
  public_property const cpObjective &  objective(void) const;
  public_property void                 removeConstraints(void);
  public_property void                 removeVariables(void);
  public_property cpVariable &         variable(tyVariableKey);
  public_property const cpVariable &   variable(tyVariableKey) const;
 };
}

// O b j e c t i v e  Interface //------------------------------------------------------------------
namespace public_area {
 /*CLASS clObjective */
 /* Represents the objective of a linear system. The parameter of the template is the type of data
    the variables of the linear system carry. */
 template <class prContent> class clObjective {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clObjective */ /* Type of constraints the objective is associated with. */
  public_property typedef clConstraint<prContent> cpConstraint;

  /*TYPE clObjective */ /* Type of linear system the objective belongs to. */
  public_property typedef clLinearSystem<prContent> cpLinearSystem;

  /*TYPE clObjective */ /* This class. */
  public_property typedef clObjective<prContent> cpObjective;

  /*TYPE clObjective */ /* Type of variable the objective is associated with. */
  public_property typedef clVariable<prContent> cpVariable;

  /*TYPE clObjective */ /* List of constraints. */
  public_property typedef std_vector(cpConstraint *) cpConstraintS;

  /*TYPE clObjective */ /* List of variables. */
  public_property typedef std_map(tyVariableKey,cpVariable *) cpVariableX;
  //-----------------------------------------------------------------------------------------Friends
  friend class clVariable<prContent>;

  friend clInStream & operator >> template_friend(prContent) (clInStream &,cpLinearSystem &);
  //-----------------------------------------------------------------------------------------Private
  private_property cpLinearSystem & atLinearSystem;

  private_property constructor clObjective(const cpObjective &);
  private_property void read(clInStream &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clObjective */ /* Coefficients of the objective. */
  read_only_attribute(clCoefficientX,atCoefficientX,coefficients);

  /*ATTRIBUTE clObjective */ /* Kind of objective. */
  read_write_attribute(tyOptimum,atKind,kind);

  public_property const cpLinearSystem & linearSystem(void) const;

  public_property constructor clObjective(cpLinearSystem &,tyOptimum=maximum);
  public_property destructor  clObjective(void);

  public_property cpObjective & operator = (const cpObjective &);
  public_property tyReal        operator [] (tyVariableKey) const;

  public_property tyReal coefficient(tyCardinal) const;
  public_property void   setCoefficient(tyVariableKey,tyReal);
  public_property tyReal value(void) const;
 };
}

// V a r i a b l e  Interface //--------------------------------------------------------------------
namespace public_area {
 /*CLASS clVariable */
 /* Represents a variable of a linear system. The parameter of the template is the type of data
    the variable carries. */
 template <class prContent> class clVariable {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clVariable */ /* Type of constraints the variable is associated with. */
  public_property typedef clConstraint<prContent> cpConstraint;

  /*TYPE clVariable */ /* Type of linear system the variable belongs to. */
  public_property typedef clLinearSystem<prContent> cpLinearSystem;

  /*TYPE clVariable */ /* Type of objective the variable is associated with. */
  public_property typedef clObjective<prContent> cpObjective;

  /*TYPE clVariable */ /* This class. */
  public_property typedef clVariable<prContent> cpVariable;

  /*TYPE clVariable */ /* List of constraints. */
  public_property typedef std_vector(cpConstraint *) cpConstraintS;

  /*TYPE clVariable */ /* List of variables. */
  public_property typedef std_map(tyVariableKey,cpVariable *) cpVariableX;
  //-----------------------------------------------------------------------------------------Private
  private_property cpLinearSystem & atLinearSystem;

  private_property constructor clVariable(const cpVariable &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clVariable */ /* Key identifying the variable in a linear system. */
  read_only_attribute(tyVariableKey,atKey,key);

  /*ATTRIBUTE clVariable */ /* Mark used by some algorithms. */
  read_write_attribute(tyMark,atMark,mark);

  /*ATTRIBUTE clVariable */ /* Kind of the variable. */
  read_write_attribute(tyVariableKind,atKind,kind);

  /*ATTRIBUTE clVariable */ /* Content of the variable. */
  read_write_attribute(prContent,atContent,content);

  /*ATTRIBUTE clVariable */ /* Value of the variable. */
  read_write_attribute(tyReal,atValue,value);

  public_property const cpLinearSystem & linearSystem(void) const;

  public_property constructor clVariable(cpLinearSystem &,const cpVariable &);
  public_property constructor clVariable(cpLinearSystem &,tyVariableKey,const prContent &);
  public_property constructor clVariable(cpLinearSystem &,tyVariableKey,tyVariableKind=realVariable,
                                         const prContent & =prContent(),tyReal=0.0);
  public_property constructor clVariable(cpLinearSystem &,clInStream &);
  public_property destructor  clVariable(void);

  public_property cpVariable & operator = (const cpVariable &);
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------ConstraintKind To String
 /*FUNCTION*/ /* Converts a constraint kind into a string. */
 inline clString constraintKindToString(tyConstraintKind agKind) {
  if (agKind==equality) return (clString("="));
  if (agKind==inferiority) return (clString("<"));
  return (clString(">"));
 }
 //--------------------------------------------------------------------------------Optimum To String
 /*FUNCTION*/ /* Converts an objective kind into a string. */
 inline clString optimumToString(tyOptimum agOptimum)
 { if (agOptimum==maximum) return (clString("maximum")); return (clString("minimum")); }
 //---------------------------------------------------------------------------VariableKind To String
 /*FUNCTION*/ /* Converts a variable kind into a string. */
 inline clString variableKindToString(tyVariableKind agKind)
 { if (agKind==realVariable) return (clString("real")); return (clString("integral")); }
}

namespace private_area {}

// C o n s t r a i n t  Inline //-------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------LinearSystem
 /*METHOD clConstraint */ /* Returns the linear system containing the constraint. */
 template <class prContent> inline
 const clLinearSystem<prContent> & clConstraint<prContent>::linearSystem(void) const
 { return (atLinearSystem); }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clConstraint */ /* Destructs and removes the constraint from its linear system. */
 template <class prContent> inline clConstraint<prContent>::~clConstraint(void) {
  cpConstraintS & lcConstraintS = atLinearSystem.atConstraintS;

  lcConstraintS.erase(std_find(lcConstraintS.begin(),lcConstraintS.end(),this));
 }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clConstraint */ /* Returns the coefficient associated with a given variable key. */
 template <class prContent>
 inline tyReal clConstraint<prContent>::operator [] (tyVariableKey agKey) const {
  clCoefficientX::const_iterator lcIterator;

  if (atLinearSystem.atVariableX.count(agKey)!=1)
   send_inline_error(erInvalidVariableKey,"constraint::operator []");

  lcIterator=atCoefficientX.find(agKey);

  if (lcIterator!=atCoefficientX.end()) return (lcIterator->second);
  else return (0.0);
 }
 //--------------------------------------------------------------------------------------Coefficient
 /*METHOD clConstraint */ /* Returns the coefficient associated with a given variable key. */
 template <class prContent>
 inline tyReal clConstraint<prContent>::coefficient(tyVariableKey agKey) const {
  clCoefficientX::const_iterator lcIterator;

  if (atLinearSystem.atVariableX.count(agKey)!=1)
   send_inline_error(erInvalidVariableKey,"constraint::coefficient");

  lcIterator=atCoefficientX.find(agKey);

  if (lcIterator!=atCoefficientX.end()) return (lcIterator->second);
  else return (0.0);
 }
 //-----------------------------------------------------------------------------------SetCoefficient
 /*METHOD clConstraint */ /* Sets the coefficient associated with a given variable key. */
 template <class prContent>
 inline void clConstraint<prContent>::setCoefficient(tyVariableKey agKey,tyReal agValue) {
  if (atLinearSystem.atVariableX.count(agKey)!=1)
   send_inline_error(erInvalidVariableKey,"constraint::setCoefficient");

  if (agValue==0.0) atCoefficientX.erase(agKey);
  else atCoefficientX[agKey]=agValue;
 }
 //-----------------------------------------------------------------------------------------IsActive
 /*METHOD clConstraint */
 /* Checks whether the constraint is active according to a given precision (default is
    <CODE>epsilon</CODE> of the <CODE>standard</CODE> module). */
 template <class prContent>
 inline tyBoolean clConstraint<prContent>::isActive(tyReal agEpsilon) const {
  tyReal lcValue = value();

  return ((atBoundary-lcValue)<=agEpsilon and (lcValue-atBoundary)<=agEpsilon);
 }
 //---------------------------------------------------------------------------------------IsViolated
 /*METHOD clConstraint */
 /* Checks whether the constraint is violated according to a given precision (default is
    <CODE>epsilon</CODE> of the <CODE>standard</CODE> module). */
 template <class prContent>
 inline tyBoolean clConstraint<prContent>::isViolated(tyReal agEpsilon) const {
  tyReal lcValue = value();

  if (atKind==inferiority) return ((lcValue-atBoundary)>agEpsilon);
  else if (atKind==superiority) return ((atBoundary-lcValue)>agEpsilon);

  return ((atBoundary-lcValue)>agEpsilon or (lcValue-atBoundary)>agEpsilon);
 }
}

// L i n e a r S y s t e m  Inline //---------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clLinearSystem */ /* Destructs the linear system. */
 template <class prContent> inline clLinearSystem<prContent>::~clLinearSystem(void) {
  removeConstraints();
  removeVariables();
  delete_object(atObjective);
 }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clLinearSystem */
 /* Returns the constraint associated with a given number. Read-write version. */
 template <class prContent>
 inline clConstraint<prContent> & clLinearSystem<prContent>::operator [] (tyCardinal agNumber) {
  if (agNumber>=atConstraintS.size())
   send_inline_error(erInvalidConstraintNumber,"linearSystem::operator []");

  return (*(atConstraintS[agNumber]));
 }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clLinearSystem */
 /* Returns the constraint associated with a given number. Read-only version. */
 template <class prContent> inline const clConstraint<prContent> &
 clLinearSystem<prContent>::operator [] (tyCardinal agNumber) const {
  if (agNumber>=atConstraintS.size())
   send_inline_error(erInvalidConstraintNumber,"linearSystem::operator []");

  return (*(atConstraintS[agNumber]));
 }
 //---------------------------------------------------------------------------------------Constraint
 /*METHOD clLinearSystem */
 /* Returns the constraint associated with a given number. Read-write version. */
 template <class prContent>
 inline clConstraint<prContent> & clLinearSystem<prContent>::constraint(tyCardinal agNumber) {
  if (agNumber>=atConstraintS.size())
   send_inline_error(erInvalidConstraintNumber,"linearSystem::constraint");

  return (*(atConstraintS[agNumber]));
 }
 //---------------------------------------------------------------------------------------Constraint
 /*METHOD clLinearSystem */
 /* Returns the constraint associated with a given number. Read-only version. */
 template <class prContent> inline
 const clConstraint<prContent> & clLinearSystem<prContent>::constraint(tyCardinal agNumber) const {
  if (agNumber>=atConstraintS.size())
   send_inline_error(erInvalidConstraintNumber,"linearSystem::constraint");

  return (*(atConstraintS[agNumber]));
 }
 //----------------------------------------------------------------------------------------Objective
 /*METHOD clLinearSystem */ /* Returns the objective of the linear system (Read-write version). */
 template <class prContent> inline
 typename clLinearSystem<prContent>::cpObjective & clLinearSystem<prContent>::objective(void)
 { return (*atObjective); }
 //----------------------------------------------------------------------------------------Objective
 /*METHOD clLinearSystem */ /* Returns the objective of the linear system (Read-only version). */
 template <class prContent> inline const typename clLinearSystem<prContent>::cpObjective &
 clLinearSystem<prContent>::objective(void) const { return (*atObjective); }
 //-----------------------------------------------------------------------------------------Variable
 /*METHOD clLinearSystem */
 /* Returns the variable associated with a given key. Read-write version. */
 template <class prContent>
 inline clVariable<prContent> & clLinearSystem<prContent>::variable(tyVariableKey agKey) {
  typename cpVariableX::const_iterator lcIterator = atVariableX.find(agKey);

  if (lcIterator==atVariableX.end())
   send_inline_error(erInvalidVariableKey,"linearSystem::variable");

  return (*(lcIterator->second));
 }
 //-----------------------------------------------------------------------------------------Variable
 /*METHOD clLinearSystem */
 /* Returns the variable associated with a given key. Read-only version. */
 template <class prContent> inline
 const clVariable<prContent> & clLinearSystem<prContent>::variable(tyCardinal agKey) const {
  typename cpVariableX::const_iterator lcIterator = atVariableX.find(agKey);

  if (lcIterator==atVariableX.end())
   send_inline_error(erInvalidVariableKey,"linearSystem::variable");

  return (*(lcIterator->second));
 }
}

// O b j e c t i v e  Inline //---------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------LinearSystem
 /*METHOD clObjective */ /* Returns the linear system containing the objective. */
 template <class prContent> inline
 const clLinearSystem<prContent> & clObjective<prContent>::linearSystem(void) const
 { return (atLinearSystem); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clObjective */
 /* Builds and adds an objective of a given kind into a linear system.
    (The default is a maximization objective.) */
 template <class prContent>
 inline clObjective<prContent>::clObjective(cpLinearSystem & agLinearSystem,tyOptimum agKind)
 : atLinearSystem(agLinearSystem),atCoefficientX(),atKind(agKind) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clObjective */ /* Destructs the objective. */
 template <class prContent> inline clObjective<prContent>::~clObjective(void) {}
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clObjective */ /* Returns the coefficient associated with a given variable key. */
 template <class prContent>
 inline tyReal clObjective<prContent>::operator [] (tyVariableKey agKey) const {
  clCoefficientX::const_iterator lcIterator;

  if (atLinearSystem.atVariableX.count(agKey)!=1)
   send_inline_error(erInvalidVariableKey,"objective::operator []");

  lcIterator=atCoefficientX.find(agKey);

  if (lcIterator!=atCoefficientX.end()) return (lcIterator->second);
  else return (0.0);
 }
 //--------------------------------------------------------------------------------------Coefficient
 /*METHOD clObjective */ /* Returns the coefficient associated with a given variable key. */
 template <class prContent>
 inline tyReal clObjective<prContent>::coefficient(tyVariableKey agKey) const {
  clCoefficientX::const_iterator lcIterator;

  if (atLinearSystem.atVariableX.count(agKey)!=1)
   send_inline_error(erInvalidVariableKey,"objective::coefficient");

  lcIterator=atCoefficientX.find(agKey);

  if (lcIterator!=atCoefficientX.end()) return (lcIterator->second);
  else return (0.0);
 }
 //-----------------------------------------------------------------------------------SetCoefficient
 /*METHOD clObjective */ /* Sets the coefficient associated with a given variable key. */
 template <class prContent>
 inline void clObjective<prContent>::setCoefficient(tyVariableKey agKey,tyReal agValue) {
  if (atLinearSystem.atVariableX.count(agKey)!=1)
   send_inline_error(erInvalidVariableKey,"objective::setCoefficient");

  if (agValue==0.0) atCoefficientX.erase(agKey);
  else atCoefficientX[agKey]=agValue;
 }
}

// V a r i a b l e  Inline //-----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------LinearSystem
 /*METHOD clVariable */ /* Returns the linear system containing the variable. */
 template <class prContent> inline
 const clLinearSystem<prContent> & clVariable<prContent>::linearSystem(void) const
 { return (atLinearSystem); }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------Constraint Operator <<
 /*FUNCTION*/ /* Writes a constraint into a stream. */
 template <class prContent>
 clOutStream & operator << (clOutStream & agStream,const clConstraint<prContent> & agConstraint) {
  method_name("constraint::operator <<");

  clCoefficientX::const_iterator lcCurrentCoefficient = agConstraint.coefficients().begin();
  clCoefficientX::const_iterator lcLastCoefficient    = agConstraint.coefficients().end();

  if (lcCurrentCoefficient==lcLastCoefficient) agStream << " " << private_area::goNullFlag;
  else {
   while (lcCurrentCoefficient!=lcLastCoefficient) {
    if ((*lcCurrentCoefficient).second!=0.0)
     agStream << (*lcCurrentCoefficient).second << " x" << (*lcCurrentCoefficient).first;

    lcCurrentCoefficient++;
    if (lcCurrentCoefficient!=lcLastCoefficient) agStream << " + ";
   }
  }

  agStream << " " << constraintKindToString(agConstraint.kind()) << " ";
  if (agConstraint.boundary()==realMax()) agStream << private_area::goPositiveInfinityFlag;
  else if (agConstraint.boundary()==realMin()) agStream << private_area::goNegativeInfinityFlag;
  else agStream << agConstraint.boundary();

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //-------------------------------------------------------------------------LinearSystem Operator <<
 /*FUNCTION*/ /* Writes a linear system into a stream. */
 template <class prContent> clOutStream &
 operator << (clOutStream & agStream,const clLinearSystem<prContent> & agLinearSystem) {
  method_name("linearSystem::operator <<");

  typedef clConstraint<prContent> cpConstraint;
  typedef clVariable<prContent>   cpVariable;

  typedef typename std_vector(cpConstraint *)::const_iterator          cpConstraintIterator;
  typedef typename std_map(tyVariableKey,cpVariable *)::const_iterator cpVariableIterator;

  cpConstraintIterator lcCurrentConstraint = agLinearSystem.constraints().begin();
  cpVariableIterator   lcCurrentVariable   = agLinearSystem.variables().begin();
  cpConstraintIterator lcLastConstraint    = agLinearSystem.constraints().end();
  cpVariableIterator   lcLastVariable      = agLinearSystem.variables().end();

  agStream << private_area::goLinearSystemStartFlag << end_line << end_line;
  agStream << private_area::goSolvedFlag << " = " << standard::string(agLinearSystem.solved());
  agStream << end_line << end_line;
  agStream << private_area::goVariablesStartFlag << end_line;

  while (lcCurrentVariable!=lcLastVariable) {
   agStream << private_area::goVariableFlag << " ";
   agStream << *((*lcCurrentVariable).second) << end_line;
   lcCurrentVariable++;
  }

  agStream << private_area::goVariablesEndFlag << end_line << end_line;
  agStream << private_area::goConstraintsStartFlag << end_line;

  while (lcCurrentConstraint!=lcLastConstraint) {
   agStream << private_area::goConstraintFlag << " = ";
   agStream << **lcCurrentConstraint << end_line;
   lcCurrentConstraint++;
  }

  agStream << private_area::goConstraintsEndFlag << end_line << end_line;
  agStream << private_area::goObjectiveFlag << " = ";
  agStream << agLinearSystem.objective() << end_line << end_line;
  agStream << private_area::goLinearSystemEndFlag << end_line;

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //----------------------------------------------------------------------------Objective Operator <<
 /*FUNCTION*/ /* Writes an objective into a stream. */
 template <class prContent>
 clOutStream & operator << (clOutStream & agStream,const clObjective<prContent> & agObjective) {
  method_name("objective::operator <<");

  clCoefficientX::const_iterator lcCurrentCoefficient = agObjective.coefficients().begin();
  clCoefficientX::const_iterator lcLastCoefficient    = agObjective.coefficients().end();

  if (lcCurrentCoefficient==lcLastCoefficient) agStream << " " << private_area::goNullFlag;
  else {
   while (lcCurrentCoefficient!=lcLastCoefficient) {
    if ((*lcCurrentCoefficient).second!=0.0)
     agStream << (*lcCurrentCoefficient).second << " x" << (*lcCurrentCoefficient).first;

    lcCurrentCoefficient++;
    if (lcCurrentCoefficient!=lcLastCoefficient) agStream << " + ";
   }
  }

  agStream << " ; " << optimumToString(agObjective.kind());

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //-----------------------------------------------------------------------------Variable Operator <<
 /*FUNCTION*/ /* Writes a variable into a stream. */
 template <class prContent>
 clOutStream & operator << (clOutStream & agStream,const clVariable<prContent> & agVariable) {
  method_name("variable::operator <<");

  agStream << "x" << agVariable.key() << " = ";
  agStream << variableKindToString(agVariable.kind());
  agStream << " ; ";

  if (agVariable.linearSystem().solved()) agStream << agVariable.value() << " ; ";
  else agStream << private_area::goUnsolvedValueFlag << " ; ";

  agVariable.content().out(agStream);

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //-------------------------------------------------------------------------LinearSystem Operator >>
 /*FUNCTION*/ /* Reads a linear system from a stream. */
 template <class prContent>
 clInStream & operator >> (clInStream & agStream,clLinearSystem<prContent> & agLinearSystem) {
  method_name("linearSystem::operator >>");

  clString lcString;

  agLinearSystem.removeConstraints();
  agLinearSystem.removeVariables();

  agStream >> lcString;
  if (lcString!=private_area::goLinearSystemStartFlag) send_error(erStreamReading);
  agStream >> lcString;
  if (lcString!=private_area::goSolvedFlag) send_error(erStreamReading);
  agStream >> lcString >> lcString;
  agLinearSystem.solved()=boolean(lcString.data());
  agStream >> lcString;
  if (lcString!=private_area::goVariablesStartFlag) send_error(erStreamReading);
  agStream >> lcString;

  while (lcString==private_area::goVariableFlag) {
   new_object(clVariable<prContent>(agLinearSystem,agStream));
   agStream >> lcString;
  }

  if (lcString!=private_area::goVariablesEndFlag) send_error(erStreamReading);
  agStream >> lcString;
  if (lcString!=private_area::goConstraintsStartFlag) send_error(erStreamReading);
  agStream >> lcString;

  while (lcString==private_area::goConstraintFlag) {
   agStream >> lcString;
   new_object(clConstraint<prContent>(agLinearSystem,agStream));
   agStream >> lcString;
  }

  if (lcString!=private_area::goConstraintsEndFlag) send_error(erStreamReading);
  agStream >> lcString;
  if (lcString!=private_area::goObjectiveFlag) send_error(erStreamReading);
  agStream >> lcString;
  agLinearSystem.objective().read(agStream);
  agStream >> lcString;
  if (lcString!=private_area::goLinearSystemEndFlag) send_error(erStreamReading);

  if (agStream.fail()) send_error(erStreamReading);
  return (agStream);
 }
}

namespace private_area {}

// C o n s t r a i n t  Implementation //-----------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------------Value
 template <class prContent> tyReal clConstraint<prContent>::value(void) const {
  method_name("constraint::value");

  typedef clCoefficientX::const_iterator                       cpCoefficientIterator;
  typedef typename cpLinearSystem::cpVariableX::const_iterator cpVariableIterator;

  tyReal        lcCoefficient;
  tyVariableKey lcKey;
  cpVariable *  lcVariable;

  cpCoefficientIterator lcCurrentCoefficient = atCoefficientX.begin();
  cpVariableIterator    lcCurrentVariable    = atLinearSystem.variables().begin();
  cpCoefficientIterator lcLastCoefficient    = atCoefficientX.end();
  cpVariableIterator    lcLastVariable       = atLinearSystem.variables().end();

  tyReal lcSum = 0.0;

  while (lcCurrentCoefficient!=lcLastCoefficient and lcCurrentVariable!=lcLastVariable) {
   lcKey=lcCurrentCoefficient->first;

   while (lcCurrentVariable->first!=lcKey and lcCurrentVariable!=lcLastVariable)
    ++lcCurrentVariable;

   if (lcCurrentVariable!=lcLastVariable) {
    lcVariable=lcCurrentVariable->second;
    lcCoefficient=lcCurrentCoefficient->second;

    lcSum+=lcCoefficient*lcVariable->value();
    ++lcCurrentCoefficient;
   }
  }

  if (lcCurrentCoefficient!=lcLastCoefficient) send_error(erInconsistentConstraintStructure);

  return (lcSum);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clConstraint */
 /* Builds and adds a copy of a constraint into a linear system. */
 template <class prContent>
 clConstraint<prContent>::clConstraint(cpLinearSystem & agLinearSystem,
                                       const cpConstraint & agConstraint)
 : atLinearSystem(agLinearSystem),atMark(agLinearSystem.atMark),
   atCoefficientX(agConstraint.atCoefficientX),atBoundary(agConstraint.atBoundary),
   atKind(agConstraint.atKind) {
  method_name("constraint::constructor");

  if (agConstraint.atLinearSystem.atVariableX.size()!=atLinearSystem.atVariableX.size())
   send_error(erIncompatibleConstraints);

  agLinearSystem.atConstraintS.push_back(this);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clConstraint */
 /* Builds and adds a constraint of a given kind into a linear system.
    (The default is an equality constraint.) */
 template <class prContent>
 clConstraint<prContent>::clConstraint(cpLinearSystem & agLinearSystem,tyConstraintKind agKind)
 : atLinearSystem(agLinearSystem),atMark(agLinearSystem.atMark),
   atCoefficientX(),atBoundary(0.0),atKind(agKind) {
  agLinearSystem.atConstraintS.push_back(this);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clConstraint */
 /* Builds and adds a constraint from an input stream into a linear system. */
 template <class prContent>
 clConstraint<prContent>::clConstraint(cpLinearSystem & agLinearSystem,clInStream & agStream)
 : atLinearSystem(agLinearSystem),atMark(agLinearSystem.atMark),atCoefficientX(),atBoundary(),
   atKind(equality) {
  method_name("constraint::constructor");

  tyBoolean lcAgain = true;

  tyReal   lcCoefficient;
  clString lcString;

  atCoefficientX.erase(atCoefficientX.begin(),atCoefficientX.end());
  agStream >> lcString;

  if (lcString!=private_area::goNullFlag) {
   do {
    lcCoefficient=real(lcString.data());
    agStream >> lcString;
    if (lcString[0]!='x') send_error(erStreamReading);
    setCoefficient(cardinal(lcString.part(1,lcString.size()).data()),lcCoefficient);

    agStream >> lcString;
    if (lcString=="+") agStream >> lcString;
    else lcAgain=false;
   }
   while (lcAgain);
  }

  atKind=constraintKind(lcString);
  agStream >> lcString;

  if (lcString==private_area::goPositiveInfinityFlag) atBoundary=realMax();
  else if (lcString==private_area::goNegativeInfinityFlag) atBoundary=realMin();
  else atBoundary=real(lcString.data());

  agLinearSystem.atConstraintS.push_back(this);

  if (agStream.fail()) send_error(erStreamReading);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clConstraint */
 /* Copies a constraint (except its key, its mark and its linear system association). */
 template <class prContent> clConstraint<prContent> &
 clConstraint<prContent>::operator = (const cpConstraint & agConstraint) {
  method_name("constraint::operator =");

  if (agConstraint.atLinearSystem.atVariableX.size()!=atLinearSystem.atVariableX.size())
   send_error(erIncompatibleConstraints);

  atCoefficientX=agConstraint.atCoefficientX;
  atBoundary=agConstraint.atBoundary;
  atKind=agConstraint.atKind;
  return (*this);
 }
}

// L i n e a r S y s t e m  Implementation //-------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------------Copy
 template <class prContent>
 void clLinearSystem<prContent>::copy(const cpLinearSystem & agLinearSystem) {
  typedef typename cpConstraintS::const_iterator cpConstraintIterator;
  typedef typename cpVariableX::const_iterator   cpVariableIterator;

  cpConstraintIterator lcCurrentConstraint = agLinearSystem.atConstraintS.begin();
  cpVariableIterator   lcCurrentVariable   = agLinearSystem.atVariableX.begin();
  cpConstraintIterator lcLastConstraint    = agLinearSystem.atConstraintS.end();
  cpVariableIterator   lcLastVariable      = agLinearSystem.atVariableX.end();

  atSolved=agLinearSystem.atSolved;

  while (lcCurrentVariable!=lcLastVariable) {
   new_object(cpVariable(*this,*(*lcCurrentVariable).second));
   lcCurrentVariable++;
  }

  while (lcCurrentConstraint!=lcLastConstraint) {
   new_object(cpConstraint(*this,**lcCurrentConstraint));
   lcCurrentConstraint++;
  }

  *atObjective=agLinearSystem.objective();
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clLinearSystem */ /* Builds an empty linear system. */
 template <class prContent> clLinearSystem<prContent>::clLinearSystem(void)
 : atObjective(nil),atSolved(false),atMark(firstMark()),atVariableX(),atConstraintS()
 { atObjective=new_object(cpObjective(*this)); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clLinearSystem */ /* Builds a copy of a linear system. */
 template <class prContent>
 clLinearSystem<prContent>::clLinearSystem(const cpLinearSystem & agLinearSystem)
 : atObjective(nil),atSolved(),atMark(firstMark()),atVariableX(),atConstraintS() {
  atObjective=new_object(cpObjective(*this));
  copy(agLinearSystem);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clLinearSystem */ /* Copies a linear system. */
 template <class prContent> clLinearSystem<prContent> &
 clLinearSystem<prContent>::operator = (const cpLinearSystem & agLinearSystem) {
  removeConstraints();
  removeVariables();
  copy(agLinearSystem);
  return (*this);
 }
 //--------------------------------------------------------------------------------RemoveConstraints
 /*METHOD clLinearSystem */ /* Removes all the constraints from the linear system. */
 template <class prContent> void clLinearSystem<prContent>::removeConstraints(void)
 { while (not atConstraintS.empty()) delete_object(*(atConstraintS.begin())); }
 //----------------------------------------------------------------------------------RemoveVariables
 /*METHOD clLinearSystem */ /* Removes all the variables from the linear system. */
 template <class prContent> void clLinearSystem<prContent>::removeVariables(void)
 { while (not atVariableX.empty()) delete_object((*(atVariableX.begin())).second); }
 //--------------------------------------------------------------------------------GetNewVariableKey
 /*METHOD clLinearSystem */
 /* Returns an unused variable key. The key given as argument is first checked and returned if
    it is unused. */
 template <class prContent>
 tyVariableKey clLinearSystem<prContent>::getNewVariableKey(tyVariableKey agKey) const {
  while (atVariableX.count(agKey)!=0) agKey=tyVariableKey(randomCardinal(cardinalMax()));

  return (agKey);
 }
 //--------------------------------------------------------------------------------GetNewVariableKey
 /*METHOD clLinearSystem */ /* Returns an unused variable key. */
 template <class prContent>
 tyVariableKey clLinearSystem<prContent>::getNewVariableKey(void) const {
  tyVariableKey lcKey;

  do { lcKey=tyVariableKey(randomCardinal(cardinalMax())); }
  while (atVariableX.count(lcKey)!=0);

  return (lcKey);
 }
}

// O b j e c t i v e  Implementation //-------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------------Read
 template <class prContent> void clObjective<prContent>::read(clInStream & agStream) {
  method_name("objective::read");

  tyBoolean lcAgain = true;

  tyReal   lcCoefficient;
  clString lcString;

  atCoefficientX.erase(atCoefficientX.begin(),atCoefficientX.end());
  agStream >> lcString;

  if (lcString!=private_area::goNullFlag) {
   do {
    lcCoefficient=real(lcString.data());
    agStream >> lcString;
    if (lcString[0]!='x') send_error(erStreamReading);
    setCoefficient(cardinal(lcString.part(1,lcString.size()).data()),lcCoefficient);

    agStream >> lcString;
    if (lcString=="+") agStream >> lcString;
    else lcAgain=false;
   }
   while (lcAgain);
  }

  if (lcString=="") send_error(erStreamReading);
  agStream >> lcString;
  atKind=optimum(lcString);
  if (agStream.fail()) send_error(erStreamReading);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clObjective */
 /* Copies an objective (except its linear system association). */
 template <class prContent>
 clObjective<prContent> & clObjective<prContent>::operator = (const cpObjective & agObjective) {
  method_name("objective::operator =");

  if (atLinearSystem.atVariableX.size()!=agObjective.atLinearSystem.atVariableX.size())
   send_error(erIncompatibleObjectives);

  atCoefficientX=agObjective.atCoefficientX;
  atKind=agObjective.atKind;
  return (*this);
 }
 //--------------------------------------------------------------------------------------------Value
 /*METHOD clObjective */
 /* Returns the value of the objective, i.e. the sum of each coefficient multiplied by the value
    of the associated variable. */
 template <class prContent> tyReal clObjective<prContent>::value(void) const {
  typedef clCoefficientX::const_iterator clCoefficientIterator;

  clCoefficientIterator lcCurrentCoefficient = atCoefficientX.begin();
  clCoefficientIterator lcLastCoefficient    = atCoefficientX.end();
  tyReal                lcSum                = 0.0;

  if (atLinearSystem.solved()) {
   while (lcCurrentCoefficient!=lcLastCoefficient) {
    lcSum+=(*lcCurrentCoefficient).second
           *atLinearSystem.variable((*lcCurrentCoefficient).first).value();

    lcCurrentCoefficient++;
   }
  }

  return (lcSum);
 }
}

// V a r i a b l e  Implementation //---------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clVariable */
 /* Builds and adds a copy of a variable into a linear system. The key is also duplicated. */
 template <class prContent>
 clVariable<prContent>::clVariable(cpLinearSystem & agLinearSystem,const cpVariable & agVariable)
 : atLinearSystem(agLinearSystem),atKey(agLinearSystem.getNewVariableKey(agVariable.atKey)),
   atMark(agLinearSystem.atMark),atKind(agVariable.atKind),atContent(agVariable.atContent),
   atValue(agVariable.atValue)
 { agLinearSystem.atVariableX.insert(std_make_pair(atKey,this)); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clVariable */
 /* Builds and adds a variable into a linear system. The content of the variable has to be
    specified. The variable is defined as a real with the value 0. */
 template <class prContent>
 clVariable<prContent>::clVariable(cpLinearSystem & agLinearSystem,tyVariableKey agKey,
                                   const prContent & agContent)
 : atLinearSystem(agLinearSystem),atKey(agKey),atMark(agLinearSystem.atMark),atKind(realVariable),
   atContent(agContent),atValue(0.0) {
  method_name("variable::constructor");

  if (agLinearSystem.atVariableX.count(atKey)==1) send_error(erVariableKeyAlreadyExists);
  agLinearSystem.atVariableX.insert(std_make_pair(atKey,this));
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clVariable */
 /* Builds and adds a variable into a linear system. All the attributes can be specified.
    (The default is a real variable set to 0 and a content defined by its default constructor.) */
 template <class prContent>
 clVariable<prContent>::clVariable(cpLinearSystem & agLinearSystem,tyVariableKey agKey,
                                   tyVariableKind agKind,const prContent & agContent,
                                   tyReal agValue)
 : atLinearSystem(agLinearSystem),atKey(agKey),atMark(agLinearSystem.atMark),atKind(agKind),
   atContent(agContent),atValue(agValue) {
  method_name("variable::constructor");

  if (agLinearSystem.atVariableX.count(atKey)==1) send_error(erVariableKeyAlreadyExists);
  agLinearSystem.atVariableX.insert(std_make_pair(atKey,this));
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clVariable */
 /* Builds and adds a variable from an input stream into a linear system. */
 template <class prContent>
 clVariable<prContent>::clVariable(cpLinearSystem & agLinearSystem,clInStream & agStream)
 : atLinearSystem(agLinearSystem),atKey(),atMark(agLinearSystem.atMark),atKind(realVariable),
   atContent(),atValue() {
  method_name("variable::constructor");

  clString lcString;

  agStream >> lcString;
  if (lcString[0]!='x') send_error(erStreamReading);
  atKey=cardinal(lcString.part(1,lcString.size()-1).data());
  if (agLinearSystem.atVariableX.count(atKey)==1) send_error(erVariableKeyAlreadyExists);
  agStream >> lcString >> lcString;
  atKind=variableKind(lcString);
  agStream >> lcString;

  if (atLinearSystem.atSolved) agStream >> atValue >> lcString;
  else {
   agStream >> lcString >> lcString;
   atValue=0.0;
  }

  atContent=prContent(agStream);
  agLinearSystem.atVariableX.insert(std_make_pair(atKey,this));

  if (agStream.fail()) send_error(erStreamReading);
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clVariable */
 /* Destructs and removes the variable from its linear system. (The associated coefficients in the
    linear system are also deleted.) */
 template <class prContent> clVariable<prContent>::~clVariable(void) {
  typedef typename cpConstraintS::iterator cpConstraintIterator;

  cpConstraintIterator lcCurrentConstraint = atLinearSystem.atConstraintS.begin();
  cpConstraintIterator lcLastConstraint    = atLinearSystem.atConstraintS.end();

  atLinearSystem.atVariableX.erase(atKey);

  while (lcCurrentConstraint!=lcLastConstraint) {
   (*lcCurrentConstraint)->atCoefficientX.erase(atKey);
   lcCurrentConstraint++;
  }

  atLinearSystem.atObjective->atCoefficientX.erase(atKey);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clVariable */
 /* Copies a variable (except its key, its mark and its linear system association). */
 template <class prContent>
 clVariable<prContent> & clVariable<prContent>::operator = (const cpVariable & agVariable) {
  atKind=agVariable.atKind;
  atContent=agVariable.atContent;
  atValue=agVariable.atValue;
  return (*this);
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// L i n e a r _ s y s t e m                                                         Implementation
// S t r u c t u r e
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "linear_system/structure.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define LINEAR_SYSTEM_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/linear_system/structure.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  linearSystemStructure
#define private_area linearSystemStructure_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Linear_system/Structure");

// Initialization //--------------------------------------------------------------------------------
#undef iniLinearSystemStructure
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erIncompatibleConstraints;
 static_error erIncompatibleObjectives;
 static_error erInconsistentConstraintStructure;
 static_error erInvalidConstraintKindString;
 static_error erInvalidConstraintNumber;
 static_error erInvalidOptimumString;
 static_error erInvalidVariableKindString;
 static_error erInvalidVariableKey;
 static_error erVariableKeyAlreadyExists;
}

// Constants & Variables //-------------------------------------------------------------------------
static_constant(tcString,goConstraintsEndFlag);
static_constant(tcString,goConstraintsStartFlag);
static_constant(tcString,goConstraintFlag);
static_constant(tcString,goLinearSystemEndFlag);
static_constant(tcString,goLinearSystemStartFlag);
static_constant(tcString,goNegativeInfinityFlag);
static_constant(tcString,goNullFlag);
static_constant(tcString,goObjectiveFlag);
static_constant(tcString,goPositiveInfinityFlag);
static_constant(tcString,goSolvedFlag);
static_constant(tcString,goUnsolvedValueFlag);
static_constant(tcString,goVariablesEndFlag);
static_constant(tcString,goVariablesStartFlag);
static_constant(tcString,goVariableFlag);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------String To ConstraintKind
 /*FUNCTION*/ /* Converts a string into a constraint kind. */
 function tyConstraintKind constraintKind(ctString & agString) {
  method_name("constraintKind");

  if (agString=="=") return (equality);
  if (agString=="<") return (inferiority);
  if (agString==">") return (superiority);
  send_error(erInvalidConstraintKindString);
  return (equality);
 }
 //--------------------------------------------------------------------------------String To Optimum
 /*FUNCTION*/ /* Converts a string into an optimum kind. */
 function tyOptimum optimum(ctString & agString) {
  method_name("optimum");

  if (agString=="minimum") return (minimum);
  if (agString=="maximum") return (maximum);
  send_error(erInvalidOptimumString);
  return (maximum);
 }
 //---------------------------------------------------------------------------String To VariableKind
 /*FUNCTION*/ /* Converts a string into a variable kind. */
 function tyVariableKind variableKind(ctString & agString) {
  method_name("variableKind");

  if (agString=="real") return (realVariable);
  if (agString=="integral") return (integralVariable);
  send_error(erInvalidVariableKindString);
  return (realVariable);
 }
}

namespace private_area {}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    erIncompatibleConstraints.create("Linear System - Incompatible constraints.");
    erIncompatibleObjectives.create("Linear System - Incompatible objectives.");
    erInconsistentConstraintStructure.create("Linear System - Inconsistent constraint structure.");
    erInvalidConstraintKindString.create("Linear System - Invalid constraint kind string.");
    erInvalidConstraintNumber.create("Linear System - Invalid constraint number.");
    erInvalidOptimumString.create("Linear System - Invalid optimum string.");
    erInvalidVariableKindString.create("Linear System - Invalid variable kind string.");
    erInvalidVariableKey.create("Linear System - Invalid variable key.");
    erVariableKeyAlreadyExists.create("Linear System - The variable key already exists.");

    goConstraintsEndFlag    = "<constraints_end>";
    goConstraintsStartFlag  = "<constraints_start>";
    goConstraintFlag        = "constraint";
    goLinearSystemEndFlag   = "<linear_system_end>";
    goLinearSystemStartFlag = "<linear_system_start>";
    goNegativeInfinityFlag  = "-oo";
    goNullFlag              = "null";
    goObjectiveFlag         = "objective";
    goPositiveInfinityFlag  = "+oo";
    goSolvedFlag            = "solved";
    goUnsolvedValueFlag     = "?";
    goVariablesEndFlag      = "<variables_end>";
    goVariablesStartFlag    = "<variables_start>";
    goVariableFlag          = "variable";
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) { environment::informTermination(goModuleName); }
}

// End //-------------------------------------------------------------------------------------------
}