Topic
  • 15 replies
  • Latest Post - ‏2010-01-18T07:46:36Z by SystemAdmin
SystemAdmin
SystemAdmin
7929 Posts

Pinned topic IloNumVarArray.setNames();

‏2009-12-29T16:40:17Z |
Could anyone give me an example of how to use this method?

I find every element in an array can be named by setName, the method of IloNumVar. So when will the setNames method be used?
And what is the difference between setName and setNames, or what are the conveniences by using setNames?

Thank you for any help and wish you guys a happy new year!
Updated on 2010-01-18T07:46:36Z at 2010-01-18T07:46:36Z by SystemAdmin
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2009-12-29T17:18:22Z  
    > jimzhang wrote:
    > Could anyone give me an example of how to use this method?
    >
    > I find every element in an array can be named by setName, the method of IloNumVar. So when will the setNames method be used?
    > And what is the difference between setName and setNames, or what are the conveniences by using setNames?
    >
    > Thank you for any help and wish you guys a happy new year!

    I don't know that I've ever used it (it doesn't exist in the Java API, and I swore off C++ years ago), but presumably it saves you the effort of writing a loop -- you pass as its argument a vector of names and it assigns them sequentially to the variables in the array. The alternative (which you have to use in Java AFAIK) is to loop through the array and invoke setName on each element of the array.

    /Paul

    Mathematicians are like Frenchmen: whenever you say something to them, they translate it into their own language, and at once it is something entirely different. (Goethe)
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2009-12-29T17:43:49Z  
    > jimzhang wrote:
    > Could anyone give me an example of how to use this method?
    >
    > I find every element in an array can be named by setName, the method of IloNumVar. So when will the setNames method be used?
    > And what is the difference between setName and setNames, or what are the conveniences by using setNames?
    >
    > Thank you for any help and wish you guys a happy new year!

    I don't know that I've ever used it (it doesn't exist in the Java API, and I swore off C++ years ago), but presumably it saves you the effort of writing a loop -- you pass as its argument a vector of names and it assigns them sequentially to the variables in the array. The alternative (which you have to use in Java AFAIK) is to loop through the array and invoke setName on each element of the array.

    /Paul

    Mathematicians are like Frenchmen: whenever you say something to them, they translate it into their own language, and at once it is something entirely different. (Goethe)
    Actually, before using setNames, all the elements in the array should be different, which means they should have been assigned different names already. So I think setNames may not save any loop for users...

    BTW: I found a lot of replies written by you when I googled the questions on clex. Thank you for your patience for anyone like me.
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2009-12-29T22:57:51Z  
    Actually, before using setNames, all the elements in the array should be different, which means they should have been assigned different names already. So I think setNames may not save any loop for users...

    BTW: I found a lot of replies written by you when I googled the questions on clex. Thank you for your patience for anyone like me.
    The argument you specify to setNames() is actually only a prefix for the
    names to be generated. The function will add the array index of each
    variable to that prefix to create a name. For example, the following code
    segment
    IloNumVarArray array(env);
    IloNumVar x(env);
    IloNumVar y(env);
    array.add(x);
    array.add(y);
    array.setNames("name");
     
    std::cout << x.getName() << ", " << y.getName() << std::endl;
    

    prints 'name[0], name[1]'.
    This provides an easy way to generate related names for variables.
    Updated on 2014-03-25T00:42:07Z at 2014-03-25T00:42:07Z by iron-man
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2009-12-29T23:16:33Z  
    The argument you specify to setNames() is actually only a prefix for the
    names to be generated. The function will add the array index of each
    variable to that prefix to create a name. For example, the following code
    segment
    <pre class="java dw" data-editor-lang="java" data-pbcklang="java" dir="ltr">IloNumVarArray array(env); IloNumVar x(env); IloNumVar y(env); array.add(x); array.add(y); array.setNames("name"); std::cout << x.getName() << ", " << y.getName() << std::endl; </pre>
    prints 'name[0], name[1]'.
    This provides an easy way to generate related names for variables.
    Does that work? When I tried this method on Microsoft Visual Studio 2007, it responses with this error:
    problem signature:
    Problem Event Name: APPCRASH
    Application Name: application_name.exe
    Application Version: 0.0.0.0
    Application Timestamp: 4b3a8aaa
    Fault Module Name: application_name.exe
    Fault Module Version: 0.0.0.0
    Fault Module Timestamp: 4b3a8aaa
    Exception Code: c0000005
    Exception Offset: 003a7854
    OS Version: 6.0.6001.2.1.0.768.3
    Locale ID: 1033
    Additional Information 1: fd00
    Additional Information 2: ea6f5fe8924aaa756324d57f87834160
    Additional Information 3: fd00
    Additional Information 4: ea6f5fe8924aaa756324d57f87834160
    That is also one of motivations of my thread posted.
    Thank you for any help.
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2009-12-30T11:39:33Z  
    Does that work? When I tried this method on Microsoft Visual Studio 2007, it responses with this error:
    problem signature:
    Problem Event Name: APPCRASH
    Application Name: application_name.exe
    Application Version: 0.0.0.0
    Application Timestamp: 4b3a8aaa
    Fault Module Name: application_name.exe
    Fault Module Version: 0.0.0.0
    Fault Module Timestamp: 4b3a8aaa
    Exception Code: c0000005
    Exception Offset: 003a7854
    OS Version: 6.0.6001.2.1.0.768.3
    Locale ID: 1033
    Additional Information 1: fd00
    Additional Information 2: ea6f5fe8924aaa756324d57f87834160
    Additional Information 3: fd00
    Additional Information 4: ea6f5fe8924aaa756324d57f87834160
    That is also one of motivations of my thread posted.
    Thank you for any help.
    Hm, it worked for me on Linux. I did not try Windows.
    Can you post your code?
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-13T05:22:27Z  
    Hm, it worked for me on Linux. I did not try Windows.
    Can you post your code?
    Sorry for the delay, I am just back from travel.

    #include <ilcplex/ilocplex.h>
    ILOSTLBEGIN

    int
    main(int argc, char **argv)
    {
    IloEnv env;
    IloNumVarArray array(env);
    IloNumVar x(env);
    IloNumVar y(env);
    array.add(x);
    array.add(y);
    array.setNames("name");
    std::cout << x.getName() << ", " << y.getName() << std::endl;
    env.end();

    return 0;
    }
    Error message:

    Problem signature:
    Problem Event Name: APPCRASH
    Application Name: CO2_Norm_Level.exe
    Application Version: 0.0.0.0
    Application Timestamp: 4b4d5869
    Fault Module Name: CO2_Norm_Level.exe
    Fault Module Version: 0.0.0.0
    Fault Module Timestamp: 4b4d5869
    Exception Code: c0000005
    Exception Offset: 002af844
    OS Version: 6.0.6001.2.1.0.768.3
    Locale ID: 1033
    Additional Information 1: fd00
    Additional Information 2: ea6f5fe8924aaa756324d57f87834160
    Additional Information 3: fd00
    Additional Information 4: ea6f5fe8924aaa756324d57f87834160

    Read our privacy statement:
    http://go.microsoft.com/fwlink/?linkid=50163&clcid=0x0409
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-13T07:13:46Z  
    Sorry for the delay, I am just back from travel.

    #include <ilcplex/ilocplex.h>
    ILOSTLBEGIN

    int
    main(int argc, char **argv)
    {
    IloEnv env;
    IloNumVarArray array(env);
    IloNumVar x(env);
    IloNumVar y(env);
    array.add(x);
    array.add(y);
    array.setNames("name");
    std::cout << x.getName() << ", " << y.getName() << std::endl;
    env.end();

    return 0;
    }
    Error message:

    Problem signature:
    Problem Event Name: APPCRASH
    Application Name: CO2_Norm_Level.exe
    Application Version: 0.0.0.0
    Application Timestamp: 4b4d5869
    Fault Module Name: CO2_Norm_Level.exe
    Fault Module Version: 0.0.0.0
    Fault Module Timestamp: 4b4d5869
    Exception Code: c0000005
    Exception Offset: 002af844
    OS Version: 6.0.6001.2.1.0.768.3
    Locale ID: 1033
    Additional Information 1: fd00
    Additional Information 2: ea6f5fe8924aaa756324d57f87834160
    Additional Information 3: fd00
    Additional Information 4: ea6f5fe8924aaa756324d57f87834160

    Read our privacy statement:
    http://go.microsoft.com/fwlink/?linkid=50163&clcid=0x0409
    Your code looks sane, so it looks like a bug in Cplex :-(
    I recall that you are using Visual Studio 2007, right?
    What version of Cplex do you use? And what version of Windows?
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-13T15:15:20Z  
    Your code looks sane, so it looks like a bug in Cplex :-(
    I recall that you are using Visual Studio 2007, right?
    What version of Cplex do you use? And what version of Windows?
    Thank you for your response,
    The OS is Windows XP Professional Version 2002.
    Service Pack 3
    I am using Microsoft Visual C++ 2008 Express Edition.
    Version of Cplex is 11.2.

    Here is some information maybe useful, what's interesting is that the message mentioned "CPLEX Callable Library" instead of "CPLEX Concert Technology"...

    <?xml version="1.0" encoding="UTF-16"?>
    <DATABASE>
    <EXE NAME="CO2_Norm_Level.exe" FILTER="GRABMI_FILTER_PRIVACY">
    <MATCHING_FILE NAME="CO2_Norm_Level.exe" SIZE="4541952" CHECKSUM="0x743A956F" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x0" LINK_DATE="01/13/2010 15:04:22" UPTO_LINK_DATE="01/13/2010 15:04:22" />
    <MATCHING_FILE NAME="cplex112.dll" SIZE="3919872" CHECKSUM="0xEEADFB08" BIN_FILE_VERSION="11.2.1.0" BIN_PRODUCT_VERSION="11.2.1.0" PRODUCT_VERSION="11.2" FILE_DESCRIPTION="CPLEX Callable Library" COMPANY_NAME="ILOG" PRODUCT_NAME="CPLEX Callable Library" FILE_VERSION="11.2.1" ORIGINAL_FILENAME="cplex112.dll" INTERNAL_NAME="cplex112.dll" LEGAL_COPYRIGHT="Copyright © ILOG 1997-2008" VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x4" VERFILETYPE="0x2" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x0" UPTO_BIN_FILE_VERSION="11.2.1.0" UPTO_BIN_PRODUCT_VERSION="11.2.1.0" LINK_DATE="11/28/2008 09:40:03" UPTO_LINK_DATE="11/28/2008 09:40:03" VER_LANGUAGE="English (United States) 0x409" />
    </EXE>
    <EXE NAME="kernel32.dll" FILTER="GRABMI_FILTER_THISFILEONLY">
    <MATCHING_FILE NAME="kernel32.dll" SIZE="989696" CHECKSUM="0x2D998938" BIN_FILE_VERSION="5.1.2600.5781" BIN_PRODUCT_VERSION="5.1.2600.5781" PRODUCT_VERSION="5.1.2600.5781" FILE_DESCRIPTION="Windows NT BASE API Client DLL" COMPANY_NAME="Microsoft Corporation" PRODUCT_NAME="Microsoft® Windows® Operating System" FILE_VERSION="5.1.2600.5781 (xpsp_sp3_gdr.090321-1317)" ORIGINAL_FILENAME="kernel32" INTERNAL_NAME="kernel32" LEGAL_COPYRIGHT="© Microsoft Corporation. All rights reserved." VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x40004" VERFILETYPE="0x2" MODULE_TYPE="WIN32" PE_CHECKSUM="0xFE572" LINKER_VERSION="0x50001" UPTO_BIN_FILE_VERSION="5.1.2600.5781" UPTO_BIN_PRODUCT_VERSION="5.1.2600.5781" LINK_DATE="03/21/2009 14:06:58" UPTO_LINK_DATE="03/21/2009 14:06:58" VER_LANGUAGE="English (United States) 0x409" />
    </EXE>
    </DATABASE>
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-13T15:17:33Z  
    Your code looks sane, so it looks like a bug in Cplex :-(
    I recall that you are using Visual Studio 2007, right?
    What version of Cplex do you use? And what version of Windows?
    I need to double check the environment of the previous try, but I also tried in the environment mentioned above, and the errors seem to be similar...
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-13T21:44:44Z  
    I need to double check the environment of the previous try, but I also tried in the environment mentioned above, and the errors seem to be similar...
    Bad news :-(
    This problem is a known issue with CPLEX 11.2, or rather Concert 2.7.
    It is fixed in more recent versions but there is no way to make this
    work in your version.
    Is this function vital for you? It should be easy to code up something
    similar.
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-13T22:47:39Z  
    Bad news :-(
    This problem is a known issue with CPLEX 11.2, or rather Concert 2.7.
    It is fixed in more recent versions but there is no way to make this
    work in your version.
    Is this function vital for you? It should be easy to code up something
    similar.
    Not really, I am just curious to know... Anyway I can use setName to assign names to every element.

    Another question related to the multi-dim variable arrays is that When I am trying to create a multi-dimensional variable array which is higher than 2 dims by C++ concert technology, I found I had to use IloArray to create a 3-dim variable array and then use this to create a 4-dim... till the # of dims I want. I am wondering if there is any other good approach to do create a multi-dimensional variable array which has dims higher than 3? What's more, I am also afraid that the higher dims of variable arrays may bring up the storage issue especially when the array is sparse after solved, it will store a lot of '0's meaning a waste of space. So is there anything I can do to avoid this happen or at least to reduce to risk of that. Thank you very much for any suggestions.
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-14T07:28:36Z  
    Not really, I am just curious to know... Anyway I can use setName to assign names to every element.

    Another question related to the multi-dim variable arrays is that When I am trying to create a multi-dimensional variable array which is higher than 2 dims by C++ concert technology, I found I had to use IloArray to create a 3-dim variable array and then use this to create a 4-dim... till the # of dims I want. I am wondering if there is any other good approach to do create a multi-dimensional variable array which has dims higher than 3? What's more, I am also afraid that the higher dims of variable arrays may bring up the storage issue especially when the array is sparse after solved, it will store a lot of '0's meaning a waste of space. So is there anything I can do to avoid this happen or at least to reduce to risk of that. Thank you very much for any suggestions.
    A very elegant solution to the multi-dimensional array problem is recursive templates.
    Once you have defined such a template you can easily define multi-dimensional arrays
    of any type. I sometimes use this one here:
    template<unsigned int D,typename T> class Array;
     
    // Partial specialization to terminate instantiation recursion.
    template<typename T>
    struct Array<1,T> {
       typedef T nested_type;
       typedef std::vector<T> container_type;
       typedef typename container_type::iterator iterator;
       typedef typename container_type::const_iterator const_iterator;
       typedef typename container_type::reverse_iterator reverse_iterator;
       typedef typename container_type::const_reverse_iterator const_reverse_iterator;
       typedef typename container_type::size_type size_type;
       typedef typename container_type::reference reference;
       typedef typename container_type::const_reference const_reference;
       typedef typename container_type::pointer pointer;
       typedef typename container_type::const_pointer const_pointer;
       typedef typename container_type::difference_type difference_type;
       typedef typename container_type::value_type value_type;
       typedef T base_type;
     
       Array() : container() {}
       template<typename I> Array(I const& i) : container(*i) {}
     
       // Default copy constructor and assignment operator are ok
       // but are expensive.
     
       iterator begin() { return container.begin(); }
       iterator end() { return container.end(); }
       const_iterator begin() const { return container.begin(); }
       const_iterator end() const { return container.end(); }
     
       reverse_iterator rbegin() { return container.rbegin(); }
       reverse_iterator rend() { return container.rend(); }
       const_reverse_iterator rbegin() const { return container.rbegin(); }
       const_reverse_iterator rend() const { return container.rend(); }
     
       reference operator[](size_type idx) { return container[idx]; }
       const_reference operator[](size_type idx) const { return container[idx]; }
       reference at(size_type idx) { return container.at(idx); }
       const_reference at(size_type idx) const { return container.at(idx); }
     
       size_type size() const { return container.size(); }   
     
       void fill(T const& t) {
          for (iterator it = begin(); it != end(); ++it)
             *it = t;
       }
     
    private:
       container_type container;
    };
     
    template<unsigned int D,typename T>
    struct Array {
       typedef Array<D-1,T> nested_type;
       typedef typename std::vector<nested_type> container_type;
       typedef typename container_type::iterator iterator;
       typedef typename container_type::const_iterator const_iterator;
       typedef typename container_type::reverse_iterator reverse_iterator;
       typedef typename container_type::const_reverse_iterator const_reverse_iterator;
       typedef typename container_type::size_type size_type;
       typedef typename container_type::reference reference;
       typedef typename container_type::const_reference const_reference;
       typedef typename container_type::pointer pointer;
       typedef typename container_type::const_pointer const_pointer;
       typedef typename container_type::difference_type difference_type;
       typedef typename container_type::value_type value_type;
       typedef T base_type;
     
       Array() : container() {}
     
       template<typename I>
       Array(I i) : container(*i, nested_type(i + 1)) {}
     
       // Default copy constructor and assignment operator are ok
       // but are expensive.
     
    // template<typename C>
    // Array(C const& c) : container(*c.begin(), c.begin() + 1) {}
     
       iterator begin() { return container.begin(); }
       iterator end() { return container.end(); }
       const_iterator begin() const { return container.begin(); }
       const_iterator end() const { return container.end(); }
     
       reverse_iterator rbegin() { return container.rbegin(); }
       reverse_iterator rend() { return container.rend(); }
       const_reverse_iterator rbegin() const { return container.rbegin(); }
       const_reverse_iterator rend() const { return container.rend(); }
     
       reference operator[](size_type idx) { return container[idx]; }
       const_reference operator[](size_type idx) const { return container[idx]; }
       reference at(size_type idx) { return container.at(idx); }
       const_reference at(size_type idx) const { return container.at(idx); }
     
       size_type size() const { return container.size(); }
     
       void fill(T const& t) {
          for (iterator it = begin(); it != end(); ++it)
             it->fill(t);
       }
     
    private:
       container_type container;
    };
    

    Example use of this template is:
    int
    main(void)
    {
       unsigned int const dim[] = { 3, 4, 5 };
       Array<3,int> array(dim);
     
       array[0][0][0] = 1;
     
       std::cout << array.size()
                 << ", " << array[0].size()
                 << ", " << array[0][0].size()
                 << std::endl;
     
       std::vector<unsigned int> dim2(dim, dim + sizeof(dim) / sizeof(dim[0]));
     
       Array<3,int> array2(dim2.begin());
       array2.fill(358);
     
       std::cout << array2.size()
                 << ", " << array2[0].size()
                 << ", " << array2[0][0].size()
                 << ", " << array2[0][1][2]
                 << std::endl;
     
       return 0;
    }
    


    The implementation above is dense, i.e. it will suffer from the memory issues
    you mentioned. In order to have a sparse version I would base the template
    definition on map rather than vector:
    template<unsigned int D,typename T> class SparseArray;
     
    // Partial specialization to terminate instantiation recursion.
    template<typename T>
    struct SparseArray<1,T> {
       enum { dimension = 1 };
       typedef std::map<int,T> container_type;
       typedef typename container_type::iterator iterator;
       typedef typename container_type::const_iterator const_iterator;
       typedef typename container_type::reverse_iterator reverse_iterator;
       typedef typename container_type::const_reverse_iterator const_reverse_iterator;
       typedef typename container_type::size_type size_type;
       typedef T &reference;
       typedef T const &const_reference;
       typedef T *pointer;
       typedef T const *const_pointer;
       typedef T base_type;
     
       SparseArray() : container() {}
     
       // Default copy constructor and assignment operator are ok
       // but are expensive.
     
       iterator begin() { return container.begin(); }
       iterator end() { return container.end(); }
       iterator find(int idx) { return container.find(idx); }
       const_iterator begin() const { return container.begin(); }
       const_iterator end() const { return container.end(); }
       const_iterator find(int idx) const { return container.find(idx); }
     
       reverse_iterator rbegin() { return container.rbegin(); }
       reverse_iterator rend() { return container.rend(); }
       const_reverse_iterator rbegin() const { return container.rbegin(); }
       const_reverse_iterator rend() const { return container.rend(); }
     
       reference operator[](size_type idx) { return container[idx]; }
       const_reference operator[](size_type idx) const { return container[idx]; }
     
       size_type size() const { return container.size(); }   
     
    private:
       container_type container;
    };
     
    template<unsigned int D,typename T>
    struct SparseArray {
       enum { dimension = D };
       typedef SparseArray<D-1,T> nested_type;
       typedef typename std::map<int,nested_type> container_type;
       typedef typename container_type::iterator iterator;
       typedef typename container_type::const_iterator const_iterator;
       typedef typename container_type::reverse_iterator reverse_iterator;
       typedef typename container_type::const_reverse_iterator const_reverse_iterator;
       typedef typename container_type::size_type size_type;
       typedef nested_type &reference;
       typedef nested_type const &const_reference;
       typedef nested_type *pointer;
       typedef nested_type const *const_pointer;
       typedef T base_type;
     
       // Default copy constructor and assignment operator are ok
       // but are expensive.
     
       iterator begin() { return container.begin(); }
       iterator end() { return container.end(); }
       iterator find(int idx) { return container.find(idx); }
       const_iterator begin() const { return container.begin(); }
       const_iterator end() const { return container.end(); }
       const_iterator find(int idx) const { return container.end(); }
     
       reverse_iterator rbegin() { return container.rbegin(); }
       reverse_iterator rend() { return container.rend(); }
       const_reverse_iterator rbegin() const { return container.rbegin(); }
       const_reverse_iterator rend() const { return container.rend(); }
     
       reference operator[](size_type idx) { return container[idx]; }
       const_reference operator[](size_type idx) const { return container[idx]; }
     
       size_type size() const { return container.size(); }
     
    private:
       container_type container;
    };
    

    Then you can do
    int
    main(void)
    {
       IloEnv env;
     
       SparseArray<3,IloNumVar> array;
     
       array[0][0][0] = IloNumVar(env, 0, 1, "x");
       array[1][2][3] = IloNumVar(env, 0, 1, "y");
     
       std::cout << array[1][2][3].getName() << std::endl
                 << array[0][0][0].getName() << std::endl;
     
       return 0;
    }
    

    Caveat:
    • Recursive templates require a decent compiler.
    • I know quite some stuff about templates but are by no means a guru. So the above examples may contain errors or stuff that can be done in a better way.
    • I designed the two templates a while ago for research purposes. I did not give them much testing in practice.
    I'd be happy to hear if you find issues with my implementation or if it did help you.
    You may also want to try to define your own recursive template. It is quite funny if you like coding :-)
    Updated on 2014-03-25T00:49:36Z at 2014-03-25T00:49:36Z by iron-man
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-14T15:06:16Z  
    A very elegant solution to the multi-dimensional array problem is recursive templates.
    Once you have defined such a template you can easily define multi-dimensional arrays
    of any type. I sometimes use this one here:
    <pre class="java dw" data-editor-lang="java" data-pbcklang="java" dir="ltr">template<unsigned int D,typename T> class Array; // Partial specialization to terminate instantiation recursion. template<typename T> struct Array<1,T> { typedef T nested_type; typedef std::vector<T> container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::reverse_iterator reverse_iterator; typedef typename container_type::const_reverse_iterator const_reverse_iterator; typedef typename container_type::size_type size_type; typedef typename container_type::reference reference; typedef typename container_type::const_reference const_reference; typedef typename container_type::pointer pointer; typedef typename container_type::const_pointer const_pointer; typedef typename container_type::difference_type difference_type; typedef typename container_type::value_type value_type; typedef T base_type; Array() : container() {} template<typename I> Array(I const& i) : container(*i) {} // Default copy constructor and assignment operator are ok // but are expensive. iterator begin() { return container.begin(); } iterator end() { return container.end(); } const_iterator begin() const { return container.begin(); } const_iterator end() const { return container.end(); } reverse_iterator rbegin() { return container.rbegin(); } reverse_iterator rend() { return container.rend(); } const_reverse_iterator rbegin() const { return container.rbegin(); } const_reverse_iterator rend() const { return container.rend(); } reference operator[](size_type idx) { return container[idx]; } const_reference operator[](size_type idx) const { return container[idx]; } reference at(size_type idx) { return container.at(idx); } const_reference at(size_type idx) const { return container.at(idx); } size_type size() const { return container.size(); } void fill(T const& t) { for (iterator it = begin(); it != end(); ++it) *it = t; } private: container_type container; }; template<unsigned int D,typename T> struct Array { typedef Array<D-1,T> nested_type; typedef typename std::vector<nested_type> container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::reverse_iterator reverse_iterator; typedef typename container_type::const_reverse_iterator const_reverse_iterator; typedef typename container_type::size_type size_type; typedef typename container_type::reference reference; typedef typename container_type::const_reference const_reference; typedef typename container_type::pointer pointer; typedef typename container_type::const_pointer const_pointer; typedef typename container_type::difference_type difference_type; typedef typename container_type::value_type value_type; typedef T base_type; Array() : container() {} template<typename I> Array(I i) : container(*i, nested_type(i + 1)) {} // Default copy constructor and assignment operator are ok // but are expensive. // template<typename C> // Array(C const& c) : container(*c.begin(), c.begin() + 1) {} iterator begin() { return container.begin(); } iterator end() { return container.end(); } const_iterator begin() const { return container.begin(); } const_iterator end() const { return container.end(); } reverse_iterator rbegin() { return container.rbegin(); } reverse_iterator rend() { return container.rend(); } const_reverse_iterator rbegin() const { return container.rbegin(); } const_reverse_iterator rend() const { return container.rend(); } reference operator[](size_type idx) { return container[idx]; } const_reference operator[](size_type idx) const { return container[idx]; } reference at(size_type idx) { return container.at(idx); } const_reference at(size_type idx) const { return container.at(idx); } size_type size() const { return container.size(); } void fill(T const& t) { for (iterator it = begin(); it != end(); ++it) it->fill(t); } private: container_type container; }; </pre>
    Example use of this template is:
    <pre class="java dw" data-editor-lang="java" data-pbcklang="java" dir="ltr">int main(void) { unsigned int const dim[] = { 3, 4, 5 }; Array<3,int> array(dim); array[0][0][0] = 1; std::cout << array.size() << ", " << array[0].size() << ", " << array[0][0].size() << std::endl; std::vector<unsigned int> dim2(dim, dim + sizeof(dim) / sizeof(dim[0])); Array<3,int> array2(dim2.begin()); array2.fill(358); std::cout << array2.size() << ", " << array2[0].size() << ", " << array2[0][0].size() << ", " << array2[0][1][2] << std::endl; return 0; } </pre>

    The implementation above is dense, i.e. it will suffer from the memory issues
    you mentioned. In order to have a sparse version I would base the template
    definition on map rather than vector:
    <pre class="java dw" data-editor-lang="java" data-pbcklang="java" dir="ltr">template<unsigned int D,typename T> class SparseArray; // Partial specialization to terminate instantiation recursion. template<typename T> struct SparseArray<1,T> { enum { dimension = 1 }; typedef std::map<int,T> container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::reverse_iterator reverse_iterator; typedef typename container_type::const_reverse_iterator const_reverse_iterator; typedef typename container_type::size_type size_type; typedef T &reference; typedef T const &const_reference; typedef T *pointer; typedef T const *const_pointer; typedef T base_type; SparseArray() : container() {} // Default copy constructor and assignment operator are ok // but are expensive. iterator begin() { return container.begin(); } iterator end() { return container.end(); } iterator find(int idx) { return container.find(idx); } const_iterator begin() const { return container.begin(); } const_iterator end() const { return container.end(); } const_iterator find(int idx) const { return container.find(idx); } reverse_iterator rbegin() { return container.rbegin(); } reverse_iterator rend() { return container.rend(); } const_reverse_iterator rbegin() const { return container.rbegin(); } const_reverse_iterator rend() const { return container.rend(); } reference operator[](size_type idx) { return container[idx]; } const_reference operator[](size_type idx) const { return container[idx]; } size_type size() const { return container.size(); } private: container_type container; }; template<unsigned int D,typename T> struct SparseArray { enum { dimension = D }; typedef SparseArray<D-1,T> nested_type; typedef typename std::map<int,nested_type> container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::reverse_iterator reverse_iterator; typedef typename container_type::const_reverse_iterator const_reverse_iterator; typedef typename container_type::size_type size_type; typedef nested_type &reference; typedef nested_type const &const_reference; typedef nested_type *pointer; typedef nested_type const *const_pointer; typedef T base_type; // Default copy constructor and assignment operator are ok // but are expensive. iterator begin() { return container.begin(); } iterator end() { return container.end(); } iterator find(int idx) { return container.find(idx); } const_iterator begin() const { return container.begin(); } const_iterator end() const { return container.end(); } const_iterator find(int idx) const { return container.end(); } reverse_iterator rbegin() { return container.rbegin(); } reverse_iterator rend() { return container.rend(); } const_reverse_iterator rbegin() const { return container.rbegin(); } const_reverse_iterator rend() const { return container.rend(); } reference operator[](size_type idx) { return container[idx]; } const_reference operator[](size_type idx) const { return container[idx]; } size_type size() const { return container.size(); } private: container_type container; }; </pre>
    Then you can do
    <pre class="java dw" data-editor-lang="java" data-pbcklang="java" dir="ltr">int main(void) { IloEnv env; SparseArray<3,IloNumVar> array; array[0][0][0] = IloNumVar(env, 0, 1, "x"); array[1][2][3] = IloNumVar(env, 0, 1, "y"); std::cout << array[1][2][3].getName() << std::endl << array[0][0][0].getName() << std::endl; return 0; } </pre>
    Caveat:
    • Recursive templates require a decent compiler.
    • I know quite some stuff about templates but are by no means a guru. So the above examples may contain errors or stuff that can be done in a better way.
    • I designed the two templates a while ago for research purposes. I did not give them much testing in practice.
    I'd be happy to hear if you find issues with my implementation or if it did help you.
    You may also want to try to define your own recursive template. It is quite funny if you like coding :-)
    Thank you so much for your help!!!

    They are very valuable to me.

    I will try if I have time.
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-14T15:26:46Z  
    setNames does not work with cplex 11.2 on windows XP 32 bit or Vista 64 bit.
    For a better way to create multi-dim variable arrays, pls refer to dju358's reply which might also reduce the risk of being out of memory.
  • SystemAdmin
    SystemAdmin
    7929 Posts

    Re: IloNumVarArray.setNames();

    ‏2010-01-18T07:46:36Z  
    Thank you so much for your help!!!

    They are very valuable to me.

    I will try if I have time.
    Another, not so complicated idea would be to define a multi-index class
    template<unsigned int D, typename T = int>
    struct MuliIndex {
       enum { dimension = D };
       T index[D];
     
       bool operator<(MultiIndex const& other) const {
          // Lexicographical comparison between this.index and other.index
          ...
       }
    };
    

    and then use std::map<MuliIndex<3>,double>.
    Updated on 2014-03-25T00:41:42Z at 2014-03-25T00:41:42Z by iron-man