Systems

A system in IBEX is a set of constraints (equalities or inequalities) with, optionnaly, a goal function to minimize and an initial domain for variables. It corresponds to the usual concept of system in mathematical programming. Here is an example of system:

Minimize \(x+y,\)

\(x \in[-1,1], y\in[-1,1]\)

such that

\(x^2+y^2\le1\)

\(y\ge x^2\).

One is usually interested in solving the system while minimizing the criterion, if any.

Class and Fields

The class for representing a system is System.

Systems fields

A system is not as simple as a collection of any constraints because each constraint must exactly relates the same set of arguments. And this set must also coincide with that of the goal function. Many algorithms of IBEX are based on this assumption. This is why they requires a system as argument (and not just an array of constraints). This makes systems a central concept in IBEX.

A system is an object of the System class. This object is made of several fields that are detailed below.

  • const int nb_var: the total number of variables or, in other words, the size of the problem. This number is basically the sum of all arguments’ components. For instance, if one declares an argument x with 10 components and an argument y with 5, the value of this field will be 15.
  • const int nb_ctr: the number of constraints.
  • Function* goal: a pointer to the goal function. If there is no goal function, this pointer is NULL.
  • Function f: the (usually vector-valued) function representing the constraints. For instance, if one defines three constraints: \(x+y\leq0,\ x-y=1\), and \(x-y\geq0\), the function f will be \((x,y)\mapsto (x+y,x-y-1,x-y)\). Note that the constraints are automatically transformed so that the right side is 0 but, however, without changing the comparison sign. It is however possible to normalize a system so that all inequalities are defined with the \(\le\) sign (see ).
  • IntervalVector box: when a system is loaded from a file, a initial box can be specified. It is contained in this field.
  • Array<NumConstraint> ctrs: the array of constraints. The Array class of IBEX can be used as a regular C array.

Auxiliary functions

(to be completed)

Creating systems (in C++)

The first alternative for creating a system is to do it programmatically, that is, directly in your C++ program. Creating a system in C++ resorts to a temporary object called a system factory. The task is done in a few simple steps:

  • declare a new system factory (an object of SystemFactory)
  • add arguments in the factory using add_var.
  • (optional) add the expression of the goal function using add_goal
  • add the constraints using add_ctr
  • create the system simply by passing the factory to the constructor of System

Here is an example:

Variable x,y;

SystemFactory fac;
fac.add_var(x);
fac.add_var(y);
fac.add_goal(x+y);
fac.add_ctr(sqr(x)+sqr(y)<=1);

System sys(fac);

If you compare the declaration of the constraint here with the examples given here, you notice that we do not list here the arguments before writing sqr(x)+sqr(y)<=1. The reason is simply that, as said above, the goal function and the constraints in a system share all the same list of arguments. This list is defined via add_var once for all.

System Transformation

We present in this section the different transformations that can be applied to a system.

Copy

The first transformation you can apply on a system is a simple copy. Of course, this is done via the copy constructor of the System class.

When calling the copy constructor, you can decide to copy everything, only the equations or only the inequalities. For this, set the second parameter of the constructor to either:

value def
COPY duplicate all the constraints
INEQ_ONLY duplicate only inequalities
EQ_ONLY duplicate only equalities

The first argument of the constructor is the system to copy of course.

	output << "original system:"         << endl;
	output << "-------------------------"<< endl;
	output << sys;
	output << "-------------------------"<< endl << endl;

	System sys2(sys,System::INEQ_ONLY);

	output << "system with only inequalities" << endl;
	output << "-------------------------"<< endl;
	output << sys2;
	output << "-------------------------"<< endl << endl;

The display is:

original system:
-------------------------
variables: 
  x, y
goal: 
  (none)
constraints:
  ((x^2+y^2)-1)<=0
  (y-x^2)>=0
  ((y+x)-1)=0
-------------------------

system with only inequalities
-------------------------
variables: 
  x, y
goal: 
  (none)
constraints:
  ((x^2+y^2)-1)<=0
  (y-x^2)>=0
-------------------------

Normalization

It is confortable in some situations to assume that a system is made of inequalities only, and that each inequality is under the forme \(g(x)\le0\), that is, it is a “less or equal” inequality. This is called a “normalized” system.

This need arises, e.g., in optimization methods where the calculation of Lagrange multipliers is simplified when the normalization assumption holds.

It is possible to automatically transform a system into a normalized one. The process is immediate. If a constraint is:

  • \(g(x)\le0\)

    it is already normalized so it is left unchanged.

  • \(g(x)<0\)

    it is replaced by \(g(x)\le0\) (yes, there is a little loss of precision here)

  • \(g(x)>0\) or \(g(x)\ge0\)

    it is replaced by \(-g(x)\le0\)

  • \(g(x)=0\)

    it is replaced by two constraints: \(g(x)\le0\) and \(-g(x)\le0\). It is also possible to introduce an inflation value or “thickness”, that is, to replace the equality by \(g(x)\le\varepsilon\) and \(-g(x)\le \varepsilon\) where \(\varepsilon\) can be fixed to any value.

Note: There is a special treatment for “thick equalities”, that is, equations of the form \(g(x)=[l,u]\). This kind of equations appear often in, e.g., robust parameter estimation problems. In this case, the equality is replaced by two inequalities, \(g(x)\le u\) and \(-g(x)\le-l\), and the \(\varepsilon\)-inflation is not applied unless \(|u-l|<\varepsilon\).

Normalization is done by calling the constructor of NormalizedSystem, a sub-class of System. Here is an example where sys is a system built previously:

	output << "original system:"         << endl;
	output << "-------------------------"<< endl;
	output << sys;
	output << "-------------------------"<< endl << endl;

	// normalize the system with a "thickness"
	// set to 0.1
	NormalizedSystem norm_sys(sys,0.1);

	output << "normalized system:"       << endl;
	output << "-------------------------"<< endl;
	output << norm_sys;
	output << "-------------------------"<< endl;

We get the following display:

original system:
-------------------------
variables: 
  x, y
goal: 
  (none)
constraints:
  ((x^2+y^2)-1)<=0
  (y-x^2)>=0
  ((y+x)-1)=0
-------------------------

normalized system:
-------------------------
variables: 
  x, y
goal: 
  (none)
constraints:
  ((x^2+y^2)-1)<=0
  (-(y-x^2))<=0
  (((y+x)-1)-0.1000000000000001)<=0
  ((-((y+x)-1))-0.1000000000000001)<=0
-------------------------

Extended System

An extended system is a system where the goal function is transformed into a constraint.

For instance, the extension of the system given above:

Minimize \(x+y,\)

\(x \in[-1,1], y\in[-1,1]\)

such that

\(x^2+y^2\le1\)

\(y\ge x^2\).

is the following unconstrained system of constraints:

\(x \in[-1,1], y\in[-1,1], \mbox{__goal__}\in(-\infty,\infty)\)

such that

\(x+y=\mbox{__goal__}\)

\(x^2+y^2\le1\)

\(y\ge x^2\)

Once built, an extended system is a system like any other one, but it has also some extra information:

  • the name of the goal variable which is automatically generated (it is “__goal__” in our previous example).
  • the index of the goal variable (the last (2) in our previous example)
  • the index of the “goal constraint” (the first (0) in our previous example)

For this reason, an extended system is represented by a subclass of System named ExtendedSystem.

To create an extended system just use the constructor of ExtendedSystem. We assume in the following example that the variable sys is a System previously built.

	output << "original system:"         << endl;
	output << "-------------------------"<< endl;
	output << sys;
	output << "-------------------------"<< endl;
	output << "  number of variables:"   << sys.nb_var  << endl;
	output << "  number of constraints:" << sys.nb_ctr  << endl << endl;

	ExtendedSystem ext_sys(sys);

	output << "extended system:"         << endl;
	output << "-------------------------"<< endl;
	output << ext_sys;
	output << "-------------------------"<< endl;
	output << "  number of variables:"   << ext_sys.nb_var << endl;
	output << "  number of constraints:" << ext_sys.nb_ctr << endl;
	output << "  goal name:"             << ext_sys.goal_name() << endl;
	output << "  goal variable:"         << ext_sys.goal_var() << endl;
	output << "  goal constraint:"       << ext_sys.goal_ctr() << endl;

We get the following display:

original system:
-------------------------
variables: 
  x, y
goal: 
  (x+y)
constraints:
  ((x^2+y^2)-1)<=0
  (y-x^2)<=0
-------------------------
  number of variables:2
  number of constraints:2

extended system:
-------------------------
variables: 
  x, y, __goal__
goal: 
  __goal__
constraints:
  ((x+y)-__goal__)=0
  ((x^2+y^2)-1)<=0
  (y-x^2)<=0
-------------------------
  number of variables:3
  number of constraints:3
  goal name:__goal__
  goal variable:2
  goal constraint:0

Fritz-John (Khun-Tucker) conditions

The generalized Khun-Tucker (aka Fritz-John) conditions can be obtained from a system. This produces a new system of n+M+R+K+1 variables where

  • n is the number of basic variables (the ones of the original system)
  • M is the number of Lagrange multipliers for inequalities (i.e., the number of inequalities in the original system)
  • R is the number of Lagrange multipliers for equalities (i.e., the number of equalities in the original system)
  • K is the number of Lagrange multipliers for bounding constraints. These bounding constraints correspond to the box field of the original system which is taken into account as 2n additional inequalities.
  • The last variable is the “special coefficient” of the goal function that is equal to 0 in the case where constraint qualification (linear independency of constraints gradients) does not hold.

Generation of the Fritz-John conditions is based on Applying a function with numerous arguments.

Example:

	output << "original system:"         << endl;
	output << "-------------------------"<< endl;
	output << sys;
	output << "-------------------------"<< endl;

	FritzJohnCond fj(sys);

	output << "Fritz-John system:"       << endl;
	output << "-------------------------"<< endl;
	output << fj << endl;
	output << "-------------------------"<< endl;
	output << "  number of variables:" << fj.nb_var << endl;

We get the following display. The variable _u is the coefficient of the goal function. The variable _l is the multiplier of the constraint.

original system:
-------------------------
variables: 
  x, y
goal: 
  (x+y)
constraints:
  ((x^2+y^2)-1)<=0
-------------------------
Fritz-John system:
-------------------------
variables: 
  x, y, _u, _l
goal: 
  (none)
constraints:
  ((_u+_l)-1)=0
  ((_u*1)+(_l*(2*x)))=0
  ((_u*1)+(_l*(2*y)))=0
  (_l*((x^2+y^2)-1))=0

-------------------------
  number of variables:4