Hi,
the way you wrote ctSAMCoverage: leads to QP
So what I would do is a variable change:
dvar float changeVar[n in Nodes][m in Nodes][t in Type];
and then
forall(n,m in Nodes,t in Type) (Locate[m][t]==0) => (changeVar[n][m][t]==0);
forall(n,m in Nodes,t in Type) (Locate[m][t]==1) => (changeVar[n][m][t]==SAMProb[n][m][t]*sum(t in Type) Locate[n][t]);
and then I would change ctSAMCoverage: into
forall (n in Nodes)
ctSAMCoverage:
(sum(t in Type, m in Nodes: (m!=n)) changeVar[n,m,t] )>= sum(t in Type) SAMCov[t]*Locate[n][t];
and then your model works fine.
I tweeted https://twitter.com/AlexFleischer1/status/843806521918132225
for this exact use case
regards
NB:
Your complete .mod
/*********************************************
* OPL 12.7.0.0 Model - 3x3 Example Code
* Author: Lessin
* Creation Date: Feb 22, 2017 at 12:52:27 PM
*********************************************/
int NumSAMTypes = ...; // Number of SAM Types
range Type = 1..NumSAMTypes;
int NumSAMNodes = ...; // Number of nodes
range Nodes = 1..NumSAMNodes;
int NumArcNodes = ...; // Number of arcs
range DualVar = 0..NumArcNodes+1;
int NumPrefPts = ...; // Number of preferential coverage points
range Prefpts = 1..NumPrefPts;
int MaxLocate[Type] = ...;
float ExpTypeWeight[Type] = ...;
float PrefCov[Prefpts] = ...;
float SAMCov[Type] = ...;
// Create a record to hold information about each arc
tuple arc {
int fromnode;
int tonode;
}
// Get the set of arcs
{arc} Arcs = ...;
float EdgeWeights1[Nodes][Arcs] = ...;
float EdgeWeights2[Nodes][Arcs] = ...;
float EdgeWeights3[Nodes][Arcs] = ...;
float EdgeWeights[n in Nodes][a in Arcs][t in Type]=(t==1)?(EdgeWeights1[n][a]):((t==2)?(EdgeWeights2[n][a]):(EdgeWeights3[n][a]));
float PrefProb1[Prefpts][Nodes] = ...;
float PrefProb2[Prefpts][Nodes] = ...;
float PrefProb3[Prefpts][Nodes] = ...;
float PrefProb[p in Prefpts][n in Nodes][t in Type]=(t==1)?(PrefProb1[p][n]):((t==2)?(PrefProb2[p][n]):(PrefProb3[p][n]));
float SAMProb1[Nodes][Nodes] = ...;
float SAMProb2[Nodes][Nodes] = ...;
float SAMProb3[Nodes][Nodes] = ...;
float SAMProb[n in Nodes][m in Nodes][t in Type]=(t==1)?(SAMProb1[n][n]):((t==2)?(SAMProb2[n][n]):(SAMProb3[n][n]));
// The network flow model has decision variables indexed on
// the arcs.
dvar float+ z;
dvar boolean Locate[Nodes][Type];
dvar float Pi[d in DualVar];
//float Duals[Arcs];
int Locate3[i in Nodes][t in Type];
dvar float changeVar[n in Nodes][m in Nodes][t in Type];
maximize z;
subject to {
forall(n,m in Nodes,t in Type) (Locate[m][t]==0) => (changeVar[n][m][t]==0);
forall(n,m in Nodes,t in Type) (Locate[m][t]==1) => (changeVar[n][m][t]==SAMProb[n][m][t]*sum(t in Type) Locate[n][t]);
//Limit number of located sites for each SAM battery type
forall (t in Type)
ctNodeLocation:
sum(n in Nodes) Locate[n][t] <= MaxLocate[t];
//Only allow one SAM battery at a given location
forall (n in Nodes)
ctLocationLimitation:
sum(t in Type) Locate[n][t] <= 1;
//Ensure coverage of preferential coverage points
forall (p in Prefpts)
ctPrefPointCoverage:
sum(t in Type, n in Nodes) PrefProb[p][n][t]*Locate[n][t] >= PrefCov[p];
//Ensure coverage of SAM batteries
// forall (n in Nodes)
// ctSAMCoverage:
// (sum(t in Type, m in Nodes: (m!=n)) SAMProb[n][m][t]*Locate[m][t])*(sum(t in Type) Locate[n][t]) >= sum(t in Type) SAMCov[t]*Locate[n][t];
forall (n in Nodes)
ctSAMCoverage:
(sum(t in Type, m in Nodes: (m!=n)) changeVar[n,m,t] )>= sum(t in Type) SAMCov[t]*Locate[n][t];
Pi[NumArcNodes+1]-Pi[0] >= z;
Pi[0] == 0;
// Dual constraints
forall (a in Arcs)
ctDual:
Pi[a.tonode]-Pi[a.fromnode] <= sum (t in Type, n in Nodes) ExpTypeWeight[t]*EdgeWeights[n][a][t]*Locate[n][t];
}
execute DISPLAY {
writeln("\nLocate SAM batteries at:\n");
for(var t in Type)
for (var n in Nodes)
if(Locate[n][t] > 0)
writeln("SAM type ",t," at Node ",n);
}
main
{
var status = 0;
thisOplModel.generate();
//cplex.epgap=0.015; //Ability to set the optimality gap to speed up solution time
if (cplex.solve())
{ //Solves the original problem
thisOplModel.postProcess();
writeln("\nInteger Model");
writeln("OBJECTIVE: ",cplex.getObjValue()); //Displays objective value of original problem
for(var a in thisOplModel.Arcs)writeln("dual CT value for:",a,"= ",thisOplModel.ctDual[a].dual); //Displays the "undefined" dual constraint values
write("\nSAMSolution = [") //Displays the SAM battery solution vector to be used for plotting purposes in MATLAB
for(var t in thisOplModel.Type) for (var n in thisOplModel.Nodes) if(thisOplModel.Locate[n][t] > 0) write(n," ")
write("];\n");
}
//Fixes the values of the original solution (Locate) in the relaxed problem (Locate3)
var Locate2=new Array(thisOplModel.Nodes.size);
for (var n in thisOplModel.Nodes) Locate2[n]=new Array(thisOplModel.Type.size);
for(var n in thisOplModel.Nodes) for(var t in thisOplModel.Type) Locate2[n][t]=thisOplModel.Locate[n][t];
for(var n in thisOplModel.Nodes) for(var t in thisOplModel.Type) thisOplModel.Locate3[n][t]=Locate2[n][t];
writeln("\nfrozen =",thisOplModel.Locate3); //Displays the fixed solution array from the original problem
//Sets the upper and lower bounds of the relaxed solution to the solution of the original problem
for(var n in thisOplModel.Nodes) for(var t in thisOplModel.Type) thisOplModel.Locate[n][t].UB=thisOplModel.Locate3[n][t];
for(var n in thisOplModel.Nodes) for(var t in thisOplModel.Type) thisOplModel.Locate[n][t].LB=thisOplModel.Locate3[n][t];
thisOplModel.convertAllIntVars();
if (cplex.solve())
{//Solves the relaxed problem
thisOplModel.postProcess();
writeln("\nRelaxed Model");
writeln("OBJECTIVE: ",cplex.getObjValue()); //Displays the objective value of the relaxed problem (should match original)
for(var a in thisOplModel.Arcs)writeln("dual CT value for:",a,"= ",thisOplModel.ctDual[a].dual); //Displays the dual values which represent the optimal path the enemy use to traverse the region
write("\nPathSolution = [ 0 ") //Displays the path solution vector to be used for plotting purposes in MATLAB
for(var a in thisOplModel.Arcs) if(thisOplModel.ctDual[a].dual > 0) write(a.tonode," ");
write("];")
write("\nTypesSolution = [") //Displays the types of SAM battery solution vector to be used for plotting purposes in MATLAB
for(var t in thisOplModel.Type) for (var n in thisOplModel.Nodes) if(thisOplModel.Locate[n][t] > 0) write(t," ");
write("];")
}
}
#DecisionOptimization#OPLusingCPLEXOptimizer