.. _secClassStructure: Class structure =============== AMPL API library consists of a collection of classes to interact with the underlying AMPL interpreter and to access its inputs and outputs. It uses generic collections to represent the various entities which comprise a mathematical model. The structure of these entities is explained in this section. Please note that all classes and functions of the AMPL API are declared in the :ns:`ampl` and :ns:`ampl.Entities` namespaces. The main class used to interact with AMPL, instantiate and interrogate the models is :class:`ampl.AMPL`. One object of this class represents an execution of an AMPL translator, and is the first class that has to be instantiated when developing a solution based on AMPL API. It allows the interaction with the underlying AMPL translator, issuing commands, getting diagnostics and controlling the process. The model entities are represented by a set of classes, schematized in figure :ref:`figCDModelEntities`. These classes represent the optimisation model being created and allow some manipulation and data assignments operations on such entities and will be presented more in detail in the section :ref:`secModellingClasses`. .. _figCDModelEntities: .. figure:: ./images/ClassDiagramModelEntitiesNew.* :align: center :width: 836 px :height: 480 px :alt: Model entities class diagram :figClass: align-center Model entities classes overview .. _secAMPLClass: AMPL class ---------- For all calculations, AMPL API uses an underlying AMPL execution engine, which is wrapped by the class :class:`ampl.AMPL`. Thus, one instance of this class is the first object to be created when writing a program which uses the AMPL API library. The object is quite resource-heavy, therefore it should be explicitly closed as soon as it is not needed anymore, with a call to :method:`ampl.AMPL.Close()` . All the model creation and structural alteration operations are to be expressed in AMPL language through the AMPL main object; moreover, the class provides access to the current state represented via the classes derived from :class:`ampl.Entity`, as shown in section :ref:`secReferenceCsharp` and provides several other functionalities. The functions can be split in three groups: direct AMPL interaction, model interrogation and commands. Direct interaction with AMPL ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The methods available to input AMPL commands are :method:`ampl.AMPL.Eval()`, :method:`ampl.AMPL.Read()` and :method:`ampl.AMPL.ReadData()`; they send the strings specified (or the specified files) to the AMPL engine for interpretation. Their async versions: :method:`ampl.AMPL.EvalAsync()`, :method:`ampl.AMPL.ReadAsync()` and :method:`ampl.AMPL.ReadDataAsync()`, permit the calling program to continue the execution while the underlying AMPL process is busy in some time consuming operation, and to define a callback to be executed when the operation is over. Model interrogation ~~~~~~~~~~~~~~~~~~~ Evaluating AMPL files or statements creates various kind of entities in the underlying AMPL process. To get the Java (or, in general, programmatic) representation of such entities, the programmer can follow two main courses. * Get a collection of all available entities, to iterate through them. The methods to obtain such lists are: * :method:`ampl.AMPL.GetVariables()` gets the map of all the defined variables * :method:`ampl.AMPL.GetConstraints()` gets the map of all the defined constraints * :method:`ampl.AMPL.GetObjectives()` gets the map of all the defined objectives * :method:`ampl.AMPL.GetSets()` gets the map of all the defined sets * :method:`ampl.AMPL.GetParameters()` gets the map of all the defined parameters * Knowing the AMPL name of an entity, use commands to get the specific entity directly: * :method:`ampl.AMPL.GetVariable()` returns the :class:`ampl.Entities.Variable` representing the AMPL variable with the specified name, if it exists * :method:`ampl.AMPL.GetConstraint()` returns the :class:`ampl.Entities.Constraint` representing the AMPL constraint with the specified name, if it exists * :method:`ampl.AMPL.GetObjective()` returns the :class:`ampl.Entities.Objective` representing the AMPL objective with the specified name, if it exists * :method:`ampl.AMPL.GetParameter()` returns the :class:`ampl.Entities.Parameter` representing the AMPL parameter with the specified name, if it exists * :method:`ampl.AMPL.GetSet()` returns the :class:`ampl.Entities.Set` representing the AMPL set with the specified name, if it exists Once the desired entities have been created, it is possible to use their properties and methods to manipulate the model and to extract or assign data. Updating the state of the programmatic entities is implemented lazily and uses proper dependency handling. Communication with the underlying engine is therefore executed only when an entity's properties are being accessed and only when necessary. An entity is invalidated (needs refreshing) if one of the entities it depends from has been manipulated or if a generic AMPL statement evaluation is performed (through :method:`ampl.AMPL.Eval()` or similar routines). This is one of the reasons why it is generally better to use the embedded functionalities (e.g. fixing a variable through the corresponding API function call) than using AMPL statements: in the latter case, the API invalidates all entities, as the effects of such generic statements cannot be predicted. Refreshing is transparent to the user, but must be taken into account when implementing functions which access data or modify entities frequently. Commands and options ~~~~~~~~~~~~~~~~~~~~ Some AMPL commands are encapsulated by functions in the :class:`ampl.AMPL` class for ease of access. These comprise :method:`ampl.AMPL.Solve()` and others. To access and set options in AMPL, the functions :method:`ampl.AMPL.GetOption()` and :method:`ampl.AMPL.SetOption()` are provided. Together with their type-safe alternatives (e.g. :method:`ampl.AMPL.GetBoolOption()`, :method:`ampl.AMPL.GetIntOption()`), these functions provide an easier programmatic access to the AMPL options. In general, when an encapsulation is available for an AMPL command, the programmatic access to it is to be preferred to calling the same command using :method:`ampl.AMPL.Eval()`. Output and errors handling ~~~~~~~~~~~~~~~~~~~~~~~~~~ Normally, output from the AMPL translator is directed to the console without passing through the C# API. This behaviour can be overriden by calling the method :method:`ampl.AMPL.EnableOutputRouting` then overriding the event :event:`ampl.AMPL.Output`, which is raised at each block of output from the translator. Error handling is two-faced: * Errors coming from the underlying AMPL translator (e.g. syntax errors and warnings obtained calling the :method:`ampl.AMPL.Eval()` method) are handled by the events :event:`ampl.AMPL.Error` and :event:`ampl.AMPL.Warning`. Note that redirection must be explicitly enabled via a call to :method:`ampl.AMPL.EnableErrorAndWarningRouting`. * Generic errors coming from the API, which are detected outside the translator are thrown as exceptions. The default implementation of the error handler throws exceptions on errors and prints the warnings to the console. .. _secModellingClasses: Modelling entities classes -------------------------- This group of classes represents the basic entities of an AMPL optimisation model: variables, constraints, objectives, parameters and sets. They are used to access the current state of the AMPL translator (e.g. to find the values of a variable), and to some extent they can be used for data input (e.g. assign values to a parameter, fix a variable). Objects of these classes cannot be created programmatically by the user: the model creation and structural modification is handled in AMPL (see section :ref:`secAMPLClass`), through the methods :method:`ampl.AMPL.Eval()` and :method:`ampl.AMPL.Read()`. The two base classes are :class:`ampl.Entities.Entity` and :class:`ampl.Instance`. The classes derived from :class:`ampl.Entities.Entity` represent algebraic entites (e.g. a variable indexed over a set in AMPL), and are implemented as a dictionary ``