Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
Expand all | Collapse all

Creating the objective function (or an expression) in C++ API takes too much time

  • 1.  Creating the objective function (or an expression) in C++ API takes too much time

    Posted 12/07/13 04:46 PM

    Originally posted by: hllsen


    Hi,

    I noticed that creating the model in C++ API takes too much time (a lot longer than it takes in OPL). Then I noticed that the following code part takes approx. 300sec.:

    double Time_start = env.getTime();
    IloExpr objfunc(env);
    for ( k = 0; k < m; ++k ) {
        for ( j = 0; j < n; ++j ) {
            objfunc += ( p[j][k] * w[j] / 2.0 ) * ( Y[k][j] + Y[k][j] * Y[k][j] );
            for (int i = 0; i < n; ++i ) {
                if ( p_over_w[k][i] < p_over_w[k][j] || ( p_over_w[k][i] == p_over_w[k][j] && i < j ) ) {
                    objfunc += (p[i][k] * w[j]) * Y[k][j] * Y[k][i];        
                }
            }
        }
    }
    std::cout <<  env.getTime() - Time_start << std::endl;
    mod.add( IloMinimize( env, objfunc ) );

    However, if I make the following [relatively] small change, it takes 12sec. to create the objective function.

    double Time_start = env.getTime();
    IloExpr objfunc(env);
    for ( k = 0; k < m; ++k ) {
        IloExpr objfunc_part(env);
        for ( j = 0; j < n; ++j ) {
            objfunc_part += ( p[j][k] * w[j] / 2.0 ) * ( Y[k][j] + Y[k][j] * Y[k][j] );
            for (int i = 0; i < n; ++i ) {
                if ( p_over_w[k][i] < p_over_w[k][j] || ( p_over_w[k][i] == p_over_w[k][j] && i < j ) ) {
                    objfunc_part += (p[i][k] * w[j]) * Y[k][j] * Y[k][i];        
                }
            }
        }
        objfunc += objfunc_part;
    }
    std::cout <<  env.getTime() - Time_start << std::endl;
    mod.add( IloMinimize( env, objfunc ) );

    In both cases  m = 6 and n = 100. I did try to use the same 'technique' to chop down objfunc_part into objfunc_part_part however it didn't save me any more  time.

    What confuses me is that creating the same objective function with the same data-set takes 0.1250 sec. in OPL Studio. Also extracting the model takes 3sec. in C++ API which is a lot longer than it takes OPL Studio to extract the same model (0.1406) .

      LOAD_MODEL ...    0.0156
      EXTRACT ...    0.1406    
        OBJECTIVE     0.1250 

    minimize
        sum(k in machines)
          sum(j in jobs)
            ( 0.5 * p[k][j] * w[j] * (y[k][j]+y[k][j]^2) + sum(i in jobs: (p_over_w[k][i] < p_over_w[k][j]) || (p_over_w[k][i] == p_over_w[k][j] && i < j)) p[k][i] * w[j] * y[k][i] * y[k][j]);

    So my question is am I doing something wrong? Are these times [300sec/12sec/3sec/0.1406sec.] reasonable? Shouldn't C++ API be faster?

    Thank you,

    halil.


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Creating the objective function (or an expression) in C++ API takes too much time

    Posted 12/08/13 11:03 AM

    I think what you observe is expected :-(

    You are suffering from the expression normalizer. You can see this easily by running your code through a profiler. Depending on how you create your expressions this normalizer may consume a considerable amount of time. To get the fastest performance for your loop just disable the normalizer for your loop and normalize the expression explicitly and only once:

    double Time_start = env.getTime();
    env.setNormalizer(false);
    IloExpr objfunc(env);
    for ( k = 0; k < m; ++k ) {
        for ( j = 0; j < n; ++j ) {
            objfunc += ( p[j][k] * w[j] / 2.0 ) * ( Y[k][j] + Y[k][j] * Y[k][j] );
            for (int i = 0; i < n; ++i ) {
                if ( p_over_w[k][i] < p_over_w[k][j] || ( p_over_w[k][i] == p_over_w[k][j] && i < j ) ) {
                    objfunc += (p[i][k] * w[j]) * Y[k][j] * Y[k][i];        
                }
            }
        }
    }
    env.setNormalizer(true);
    objfunc.normalize();

    std::cout <<  env.getTime() - Time_start << std::endl;
    mod.add( IloMinimize( env, objfunc ) );

    That did the trick for me.

    I don't know what OPL does internally but I guess it does something similar or just knows how build expressions and avoid invoking the normalizer too often.


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Creating the objective function (or an expression) in C++ API takes too much time

    Posted 12/08/13 02:20 PM

    Originally posted by: hllsen


    Thank you Daniel. That did the trick for me too. I even realized that I don't need to normalize this specific model, and after turning it all the way off model extraction is also faster now (it was 3 seconds and now it is instantaneous).


    #CPLEXOptimizers
    #DecisionOptimization