0

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.

Hung H
  • 1

1 Answers1

0

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.

  • Thanks a lot for your detailed reply! I wasn't clear in my request. To add more context, I'm building an optimisation model, and the indices of the some variables may be extended in the future, but it's not known now. I'm thinking of a way to make adding an index to the variable easy, without changing in 1000 of places where I use the variable in the code. As an example, say I want to have a variable like `pizza(SIZE, MAIN_TOPPING)` but maybe six months later, I need to expand the variable to `pizza(SIZE, MAIN_TOPPING, INSTAGRAMMABILITY_SCORE)`. I think declaring a type may help. – Hung H Mar 17 '23 at 15:27
  • In this case it might be a good idea to encapsulate the details of your index in a record (https://www.fico.com/fico-xpress-optimization/docs/latest/mosel/UG/dhtml/moselugB2.html?scroll=secB2initrec) and then use that record for indexing. Then you can always change the record definition in a single place. However, all this may be over-engineering: if the dimension of one of your variables change, then probably also the semantics change. And even if not, it might be a good idea to force people to look at each place again to make sure things still have the correct semantic with one dim added. – Daniel Junglas Mar 21 '23 at 14:28