Dynamic number of indices in Xpress

94 Views Asked by At

I want to have a variable where depending on the use cases may have different number of indices.

That is in some cases, the variable may be of the form V: array(set of string, set of string) of mpvar, while in some other cases, it may be V: array(set of string, set of string, set of string) of mpvar.

Is there a way to declare and use variables with a dynamic number of indices?

I've read the documentation of Xpress but haven't managed to find a solution.

1

There are 1 best solutions below

2
Susanne Heipcke On

How to address this question will to a large extend depend on the way how this array of variables is used. How is the array accessed / enumerated (always in its entirety, or are you building constraint expressions over certain indices)? How do you decide whether there are 2 or 3 indices (at compile time or data-driven at run time)?

Within a single model it is not possible to declare (globally) an array with 2 different sets of indices, however, multiple declarations (along with their use) could be provided in various different ways, eg through separately compiled portions of code.

  1. The technically easiest solution probably would be to declare the array with the full set of indices, populating any unused index set with a single default value. This way you avoid having to specify several cases when accessing the array, eg in the definition of constraints.
  2. Using the concepts of union types and references that have been introduced in Mosel 6, you can work with some constructs like the following (without any further detail it is difficult to tell whether this representation is practical for your use case):
model "mytestmodel"
 uses 'mmreflect'
 parameters
   NDIM=2
 end-parameters
     
 declarations
  ! Type declarations
   a2d=array(set of string,set of string) of mpvar
   a3d=array(set of string,set of string,set of string) of mpvar
  ! The array of variables
   v: any
  ! Declaration of a subroutine
   procedure printsol(a: any)
 end-declarations
    
 if NDIM=2 then v:=->(a2d)
   forall(j in ['b1','b2','b3']) create(v.a2d('a',j))
 elif NDIM=3 then
   v:=->(a3d)
   forall(j in ['b1','b2','b3']) create(v.a3d('a',j,"c"))
 else
   writeln("Bad array size")
 end-if
    
 writeln("Number of array dimensions=", v.array.nbdim)
 printsol(v)
    
 procedure printsol(a: any)
   declarations
     it: iterator
   end-declarations
   if a is array of mpvar then
     inititer(it,a.array)
     while (nextcell(it)) writeln(it.indices, ":", a.array(it).mpvar.sol)
   else
     writeln("Unexpected data structure")
   end-if 
 end-procedure
    
end-model

There are various other options (among others, local declarations within subroutines, using preprocessor markup to select portions of code for compilation, or working with dynamically loaded Mosel packages), but deciding what would be a good choice really depends on your specific use case.