//public void InitialEstimatedCost(CRegion sscrg, double[,] padblTD, int intEstSteps) //{ // this.dblCostEstType = 0; // foreach (var kvp in this.CphTypeIndexSD_Area_CphGID) // { // //there is only one element in targetCrg // this.dblCostEstType += kvp.Key.dblArea * padblTD[kvp.Value, sscrg.GetSoloCphTypeIndex()]; // } // this.dblCostEstType = intEstSteps * this.dblCostEstType; // if (CConstants.strShapeConstraint == "MaximizeMinArea") // { // //this.dblCostEstArea = intEstSteps * EstimateSumMinArea(this); // //this.dblCostEst += this.dblCostEstArea; // } // else if (CConstants.strShapeConstraint == "MaximizeAvgComp_EdgeNumber") // { // this.dblCostEstComp = intEstSteps * BalancedEstAvgComp_EdgeNumber(this, this, sscrg); // } // else if (CConstants.strShapeConstraint == "MaximizeMinComp_Combine") // { // this.dblCostEstComp = intEstSteps * BalancedEstMinComp_Combine(this, this, sscrg); // } // else if (CConstants.strShapeConstraint == "MaximizeMinComp_EdgeNumber") // { // this.dblCostEstComp = intEstSteps * BalancedEstMinComp_EdgeNumber(this, this, sscrg); // } // else if (CConstants.strShapeConstraint == "MinimizeInteriorBoundaries") // { // this.dblCostEstComp = intEstSteps * BalancedEstCompInteriorLength_Basic(this, this); // } // this.dblCostEst = (1 - CAreaAgg_Base.dblLamda) * this.dblCostEstType + // CAreaAgg_Base.dblLamda * this.dblArea * this.dblCostEstComp; // this.d = this.dblCostEst; //} /// <summary> /// /// </summary> /// <param name="activecph"></param> /// <param name="passivecph"></param> /// <param name="unitedcph"></param> /// <param name="SSCph"></param> /// <param name="NewCrg"></param> /// <param name="padblTD"></param> /// <remarks>if we change the cost method, then we will also need to /// change the codes of InitialSubCostEstimated in CRegion.cs, the codes of updating existing outcrg </remarks> public void ComputeEstCost(CRegion lscrg, CRegion sscrg, CRegion NewCrg, double[,] padblTD, int intEstSteps) { NewCrg.dblCostEstType = BalancedEstType(NewCrg, sscrg.GetSoloCphTypeIndex(), padblTD, intEstSteps); if (CConstants.strShapeConstraint == "MaximizeMinArea") { //NewCrg.dblCostEstArea = intEstSteps*EstimateSumMinArea(NewCrg); //will we do this twice???? //NewCrg.dblCostEst = NewCrg.dblCostEstType + NewCrg.dblCostEstArea; } else if (CConstants.strShapeConstraint == "MaximizeAvgComp_EdgeNumber") { NewCrg.dblCostEstComp = BalancedEstAvgComp_EdgeNumber(NewCrg, lscrg, sscrg, intEstSteps); //to make dblCostEstComp comparable to dblCostEstType and to avoid digital problems, we time dblCostEstComp by area //we will adjust the value later NewCrg.dblCostEst = (1 - CAreaAgg_Base.dblLamda) * NewCrg.dblCostEstType + CAreaAgg_Base.dblLamda * NewCrg.dblArea * NewCrg.dblCostEstComp; } else if (CConstants.strShapeConstraint == "MaximizeAvgComp_Combine") { } else if (CConstants.strShapeConstraint == "MaximizeMinComp_Comine") { //NewCrg.dblCostEstComp = intEstSteps * BalancedEstMinComp_Combine(NewCrg, lscrg, sscrg); ////to make dblCostEstComp comparable to dblCostEstType and to avoid digital problems, we time dblCostEstComp by area ////we will adjust the value later //NewCrg.dblCostEst = (1 - CAreaAgg_Base.dblLamda) * NewCrg.dblCostEstType + // CAreaAgg_Base.dblLamda * NewCrg.dblArea * NewCrg.dblCostEstComp; } else if (CConstants.strShapeConstraint == "MaximizeMinComp_EdgeNumber") { //NewCrg.dblCostEstComp = intEstSteps * BalancedEstMinComp_EdgeNumber(NewCrg, lscrg, sscrg); ////to make dblCostEstComp comparable to dblCostEstType and to avoid digital problems, we time dblCostEstComp by area ////we will adjust the value later //NewCrg.dblCostEst = (1 - CAreaAgg_Base.dblLamda) * NewCrg.dblCostEstType + // CAreaAgg_Base.dblLamda * NewCrg.dblArea * NewCrg.dblCostEstComp; } else if (CConstants.strShapeConstraint == "MinimizeInteriorBoundaries") { NewCrg.dblCostEstComp = BalancedEstCompInteriorLength_Basic(NewCrg, lscrg, intEstSteps); //to make dblCostEstComp comparable to dblCostEstType and to avoid digital problems, we time dblCostEstComp by area //we will adjust the value later NewCrg.dblCostEst = (1 - CAreaAgg_Base.dblLamda) * NewCrg.dblCostEstType + CAreaAgg_Base.dblLamda * NewCrg.dblArea * NewCrg.dblCostEstComp; } else if (CConstants.strShapeConstraint == "NonShape") { NewCrg.dblCostEst = NewCrg.dblCostEstType; } //double dblWeight = 0.5; NewCrg.d = NewCrg.dblCostExact + NewCrg.dblCostEst; }
/// <summary> /// /// </summary> /// <param name="LSCrg"></param> /// <param name="SSCrg"></param> /// <param name="StrObjLtDt"></param> /// <param name="adblTD"></param> /// <param name="EstStepsCostVPDt">Results from A*</param> /// <param name="strAreaAggregation"></param> /// <returns></returns> public CRegion Greedy(CRegion LSCrg, CRegion SSCrg, CStrObjLtDt StrObjLtDt, double[,] adblTD, Dictionary <int, CValPair <int, double> > EstStepsCostVPDt, string strAreaAggregation) { long lngStartMemory = GC.GetTotalMemory(true); var pStopwatchOverHead = Stopwatch.StartNew(); var ExistingCorrCphsSD0 = LSCrg.SetInitialAdjacency(); //also count the number of edges AddLineToStrObjLtDt(StrObjLtDt, LSCrg); Console.WriteLine(); Console.WriteLine("Crg: ID " + LSCrg.ID + "; n " + LSCrg.GetCphCount() + "; m " + LSCrg.AdjCorrCphsSD.Count + " " + CConstants.strShapeConstraint + " " + strAreaAggregation); long lngTimeOverHead = pStopwatchOverHead.ElapsedMilliseconds; pStopwatchOverHead.Stop(); var pStopwatchLast = new Stopwatch(); long lngTime = 0; CRegion resultcrg = new CRegion(-2); try { pStopwatchLast.Restart(); var ExistingCorrCphsSD = new SortedDictionary <CCorrCphs, CCorrCphs> (ExistingCorrCphsSD0, ExistingCorrCphsSD0.Comparer); LSCrg.cenumColor = CEnumColor.white; resultcrg = Compute(LSCrg, SSCrg, SSCrg.GetSoloCphTypeIndex(), strAreaAggregation, ExistingCorrCphsSD, StrObjLtDt, adblTD); } catch (System.OutOfMemoryException ex) { Console.WriteLine(ex.Message); } lngTime = pStopwatchLast.ElapsedMilliseconds + lngTimeOverHead; Console.WriteLine("d: " + resultcrg.d + " Type: " + resultcrg.dblCostExactType + " Compactness: " + resultcrg.dblCostExactComp); EstStepsCostVPDt.TryGetValue(LSCrg.ID, out CValPair <int, double> outEstStepsCostVP); if (outEstStepsCostVP.val1 == 0 && CCmpMethods.CmpDbl_CoordVerySmall(outEstStepsCostVP.val2, resultcrg.d) == 0) { StrObjLtDt.SetLastObj("EstSteps/Gap%", 0); //optimal solutions } else { StrObjLtDt.SetLastObj("EstSteps/Gap%", 100); //not sure, at least feasible solutions } //we don't need to +1 because +1 is already included in _intStaticGID //int intExploredRegionAll = CRegion._intStaticGID - CRegion._intStartStaticGIDLast; StrObjLtDt.SetLastObj("#Edges", CRegion._intEdgeCount); StrObjLtDt.SetLastObj("Time_F(ms)", lngTime); StrObjLtDt.SetLastObj("Time_L(ms)", lngTime); StrObjLtDt.SetLastObj("Time(ms)", lngTime); StrObjLtDt.SetLastObj("Memory(MB)", CHelpFunc.GetConsumedMemoryInMB(false, lngStartMemory)); Console.WriteLine("We have visited " + CRegion._intNodeCount + " Nodes and " + CRegion._intEdgeCount + " Edges."); return(resultcrg); }
private CRegion ComputeAccordEstSteps(CRegion LSCrg, CRegion SSCrg, string strAreaAggregation, SortedDictionary <CCorrCphs, CCorrCphs> ExistingCorrCphsSD, int intEstSteps, CStrObjLtDt StrObjLtDt, double[,] padblTD, int intQuitCount = 200000) { int intRegionID = LSCrg.ID; //all the regions generated in this function will have the same intRegionID ComputeEstCost(LSCrg, SSCrg, LSCrg, padblTD, intEstSteps); //LSCrg.InitialEstimatedCost(SSCrg, padblTD, intEstSteps); //LSCrg.SetCoreCph(intSSTypeIndex); //a region represents a node in graph, ExistingCrgSD stores all the nodes //we use this dictionary to make sure that if the two patches have the same cpgs, then they have the same GID var ExistingCphSDLt = new List <SortedDictionary <CPatch, CPatch> >(LSCrg.GetCphCount() + 1); for (int i = 0; i < ExistingCphSDLt.Capacity; i++) { var Element = new SortedDictionary <CPatch, CPatch>(CPatch.pCmpCPatch_CpgGID); ExistingCphSDLt.Add(Element); } var ExistingCrgSDLt = new List <SortedDictionary <CRegion, CRegion> >(LSCrg.GetCphCount() + 1); for (int i = 0; i < ExistingCrgSDLt.Capacity; i++) { //we don't compare exact cost first because of there may be rounding problems var Element = new SortedDictionary <CRegion, CRegion>(CRegion.pCmpCrg_CphGIDTypeIndex); ExistingCrgSDLt.Add(Element); } ExistingCrgSDLt[LSCrg.GetCphCount()].Add(LSCrg, LSCrg); var FinalOneCphCrg = new CRegion(intRegionID); var Q = new SortedSet <CRegion>(CRegion.pCmpCrg_Cost_CphGIDTypeIndex); int intCount = 0; CRegion._intNodeCount = 1; CRegion._intEdgeCount = 0; Q.Add(LSCrg); while (true) { intCount++; var u = Q.Min; if (Q.Remove(u) == false) { throw new ArgumentException ("cannot move an element in this queue! A solution might be to make dblVerySmall smaller!"); } u.cenumColor = CEnumColor.black; //List<CRegion> crgcol = new List<CRegion>(); //crgcol.Add(u); //OutputMap(crgcol, this._TypePVDt, u.d, intCount, pParameterInitialize); //MessageBox.Show("click for next!"); //if (CConstants.strShapeConstraint == "MaximizeMinComp_EdgeNumber" || // CConstants.strShapeConstraint == "MinimizeInteriorBoundaries") //{ // Console.WriteLine("Crg: ID " + u.ID + "; GID:" + u.GID + "; CphNum:" + u.GetCphCount() + // "; d:" + u.d / u.dblArea + "; ExactCost:" + u.dblCostExact / u.dblArea + // "; Compactness:" + u.dblCostExactComp + "; Type:" + u.dblCostExactType / u.dblArea); //} //else if (CConstants.strShapeConstraint == "NonShape") //{ // Console.WriteLine("Crg: ID " + u.ID + "; GID:" + u.GID + "; CphNum:" + u.GetCphCount() + // "; d:" + u.d + "; ExactCost:" + u.dblCostExactType); //} //at the beginning, resultcrg.d is double.MaxValue. //Later, when we first encounter that there is only one CPatch in LSCrg, //resultcrg.d will be changed to the real cost //u.d contains estimation, and resultcrg.d doesn't contains. //if u.d > resultcrg.d, then resultcrg.d must already be the smallest cost if (u.GetCphCount() == 1) { if (u.GetSoloCphTypeIndex() == SSCrg.GetSoloCphTypeIndex()) { //Console.WriteLine("The number of nodes we can forget: " + intCount); //Console.WriteLine("The nodes in the stack: " + Q.Count); //int intCrgCount = 0; //foreach (var item in ExistingCrgSDLt) //{ // intCrgCount += item.Count; //} FinalOneCphCrg = u; break; } else { throw new ArgumentException("this is impossible!"); //continue; } } foreach (var newcrg in AggregateAndUpdateQ(u, LSCrg, SSCrg, Q, strAreaAggregation, ExistingCrgSDLt, ExistingCphSDLt, ExistingCorrCphsSD, _adblTD, intEstSteps)) { //int intExploredRegionLast = CRegion._intStaticGID - CRegion._intStartStaticGIDLast; //we don't need to +1 because +1 is already included in _intStaticGID if (CRegion._intNodeCount > intQuitCount) { //if we have visited 2000000 regions but haven't found an optimum aggregation sequence, //then we return null and overestimate in the heuristic function return(new CRegion(-2)); } } } RecordResultForCrg(StrObjLtDt, LSCrg, FinalOneCphCrg, SSCrg.GetSoloCphTypeIndex()); return(FinalOneCphCrg); }
// Step 4 ***************************************************************************************************** // Step 4 ***************************************************************************************************** internal static void PopulateByRow(IMPModeler model, out IIntVar[][][] var2, out IIntVar[][][][] var3, out IIntVar[][][][][] var4, out IRange[][] rng, CRegion lscrg, CRegion sscrg, double[,] adblTD, string strAreaAggregation) { var aCph = lscrg.GetCphCol().ToArray(); int intCpgCount = lscrg.GetCphCount(); //double dblILPSmallValue = 0.000000001; //double dblILPSmallValue = 0; var x = new IIntVar[intCpgCount][][]; for (int i = 0; i < intCpgCount; i++) { x[i] = new IIntVar[intCpgCount][]; for (int j = 0; j < intCpgCount; j++) { x[i][j] = model.BoolVarArray(intCpgCount); } } //cost in terms of type change var y = Generate4DNumVar(model, intCpgCount - 1, intCpgCount, intCpgCount, intCpgCount); //cost in terms of compactness (length of interior boundaries) var z = Generate4DNumVar(model, intCpgCount - 2, intCpgCount, intCpgCount, intCpgCount); var c = Generate4DNumVar(model, intCpgCount - 2, intCpgCount, intCpgCount, intCpgCount); var3 = new IIntVar[1][][][]; var4 = new IIntVar[3][][][][]; var3[0] = x; var4[0] = y; var4[1] = z; var4[2] = c; //model.AddEq(x[2][0][3], 1.0, "X1"); //model.AddEq(x[2][1][3], 1.0, "X2"); //model.AddEq(x[2][2][2], 1.0, "X3"); //model.AddEq(x[2][3][3], 1.0, "X4"); //add minimizations ILinearNumExpr pTypeCostExpr = model.LinearNumExpr(); //ILinearNumExpr pTypeCostAssitantExpr = model.LinearNumExpr(); for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { for (int l = 0; l < intCpgCount; l++) { double dblCoe = aCph[j].dblArea * adblTD[aCph[k].intTypeIndex, aCph[l].intTypeIndex]; pTypeCostExpr.AddTerm(y[i][j][k][l], dblCoe); //pTypeCostAssitantExpr.AddTerm(y[i][j][k][l], dblILPSmallValueMinimization); } } } } //this is actually for t=1, whose compactness is known double dblCompCostFirstPart = 0; ILinearNumExpr pCompCostSecondPartExpr = model.LinearNumExpr(); var pAdjCorrCphsSD = lscrg.AdjCorrCphsSD; double dblConst = Convert.ToDouble(intCpgCount - 1) / Convert.ToDouble(intCpgCount - 2); for (int i = 0; i < intCpgCount - 2; i++) //i represents indices { double dblNminusT = intCpgCount - i - 2; //double dblTemp = (intCpgCount - i) * dblConst; dblCompCostFirstPart += 1 / dblNminusT; double dblSecondPartDenominator = lscrg.dblInteriorSegLength * dblNminusT * 2; //we don't need to divide the value by 2 because every boundary is only counted once foreach (var pCorrCphs in pAdjCorrCphsSD.Keys) { for (int l = 0; l < intCpgCount; l++) { pCompCostSecondPartExpr.AddTerm(pCorrCphs.dblSharedSegLength / dblSecondPartDenominator, z[i][pCorrCphs.FrCph.ID][pCorrCphs.ToCph.ID][l]); pCompCostSecondPartExpr.AddTerm(pCorrCphs.dblSharedSegLength / dblSecondPartDenominator, z[i][pCorrCphs.ToCph.ID][pCorrCphs.FrCph.ID][l]); } } //var pSecondPartExpr = model.Prod(pCompCostSecondPartExpr, 1 / dblSecondPartDenominator); } if (intCpgCount == 1) { model.AddMinimize(pTypeCostExpr); //we just use an empty expression } else { //Our Model*************************************** var Ftp = model.Prod(pTypeCostExpr, 1 / lscrg.dblArea); var Fcp = model.Prod(dblConst, model.Sum(dblCompCostFirstPart, model.Negative(pCompCostSecondPartExpr))); //model.AddMinimize(model.Prod(model.Sum(Ftp, Fcp), 0.5)); model.AddMinimize(model.Sum( model.Prod(1 - CAreaAgg_Base.dblLamda, Ftp), model.Prod(CAreaAgg_Base.dblLamda, Fcp))); //model.AddMinimize(Fcp); //model.AddMaximize(Fcp); //model.AddObjective() } //for showing slacks var IRangeLt = new List <IRange>(); //a polygon $p$ is assigned to exactly one polygon at a step $t$ for (int i = 0; i < intCpgCount; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { ILinearNumExpr pOneCenterExpr = model.LinearNumExpr(); for (int l = 0; l < intCpgCount; l++) { pOneCenterExpr.AddTerm(x[i][j][l], 1.0); } model.AddEq(pOneCenterExpr, 1.0, "AssignToOnlyOneCenter"); } } //polygon $r$, which is assigned by other polygons, must be a center for (int i = 0; i < intCpgCount; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int l = 0; l < intCpgCount; l++) { model.AddLe(x[i][j][l], x[i][l][l], "AssignedIsCenter__" + i + "__" + j + "__" + l); } } } //only one patch is aggregated into another patch at each step for (int i = 0; i < intCpgCount; i++) //i represents indices { ILinearNumExpr pOneAggregationExpr = model.LinearNumExpr(); for (int j = 0; j < intCpgCount; j++) { pOneAggregationExpr.AddTerm(x[i][j][j], 1.0); } model.AddEq(pOneAggregationExpr, intCpgCount - i, "CountCenters"); } //a center can disappear, but will never reappear afterwards for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { model.AddGe(x[i][j][j], x[i + 1][j][j], "SteadyCenters"); } } //to make sure that the final aggregated polygon has the same color as the target polygon ILinearNumExpr pFinalStateExpr = model.LinearNumExpr(); int intTypeIndexGoal = sscrg.GetSoloCphTypeIndex(); for (int i = 0; i < intCpgCount; i++) { if (aCph[i].intTypeIndex == intTypeIndexGoal) { pFinalStateExpr.AddTerm(x[intCpgCount - 1][i][i], 1.0); } } model.AddEq(pFinalStateExpr, 1.0, "EnsureTarget"); //to restrict *y* for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { //IRangeLt.Add(model.AddLe(model.Sum(y[i][j][k][k], x[i][j][k], x[i + 1][j][k]), 2.0 , "RestrictY")); for (int l = 0; l < intCpgCount; l++) { var LieYRight = model.LinearIntExpr(-1); LieYRight.AddTerm(x[i][j][k], 1); LieYRight.AddTerm(x[i + 1][j][l], 1); model.AddGe(y[i][j][k][l], LieYRight, "RestrictY1"); model.AddLe(y[i][j][k][l], x[i][j][k], "RestrictY2"); model.AddLe(y[i][j][k][l], x[i + 1][j][l], "RestrictY3"); } } } } //to restrict *z* for (int i = 0; i < intCpgCount - 2; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { //for (int k = j; k < intCpgCount; k++) // pay attention for (int k = 0; k < intCpgCount; k++) { for (int l = 0; l < intCpgCount; l++) { var LieZRight = model.LinearIntExpr(-1); LieZRight.AddTerm(x[i + 1][j][l], 1); LieZRight.AddTerm(x[i + 1][k][l], 1); model.AddGe(z[i][j][k][l], LieZRight, "RestrictZ1"); model.AddLe(z[i][j][k][l], x[i + 1][j][l], "RestrictZ2"); model.AddLe(z[i][j][k][l], x[i + 1][k][l], "RestrictZ3"); } } } } //to restrict *c* double dblCpgCountReciprocal = 1 / Convert.ToDouble(intCpgCount); for (int i = 0; i < intCpgCount - 2; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { //for (int k = j; k < intCpgCount; k++) // pay attention for (int k = 0; k < intCpgCount; k++) { for (int l = 0; l < intCpgCount; l++) { if (k == l) { continue; } model.AddLe(c[i][j][k][l], x[i][j][k], "RestrictC1"); var pLieContiguityExpr = model.LinearIntExpr(); //pContiguityExpr.AddTerm(x[i][j][k], 1.0); //including polygon j itself foreach (var pAdjacentCph in aCph[j].AdjacentCphSS) { pLieContiguityExpr.AddTerm(x[i][pAdjacentCph.ID][l], 1); } model.AddLe(c[i][j][k][l], pLieContiguityExpr, "Contiguity"); foreach (var pAdjacentCph in aCph[j].AdjacentCphSS) { var pContiguityExpr2 = model.LinearNumExpr(-1); pContiguityExpr2.AddTerm(x[i][j][k], 1); pContiguityExpr2.AddTerm(x[i][pAdjacentCph.ID][l], 1); model.AddGe(c[i][j][k][l], pContiguityExpr2, "Contiguity2"); } var pContiguityExprRight3 = model.LinearIntExpr(); for (int m = 0; m < intCpgCount; m++) { pContiguityExprRight3.AddTerm(c[i][m][k][l], 1); } model.AddLe(y[i][k][k][l], pContiguityExprRight3, "Contiguity3"); } } } } //If two polygons have been aggregated into one polygon, then they will //be aggregated together in later steps. Our sixth constraint achieve this by requiring for (int i = 0; i < intCpgCount - 3; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { var pAssignTogetherExprPre = model.LinearIntExpr(); var pAssignTogetherExprAfter = model.LinearIntExpr(); for (int l = 0; l < intCpgCount; l++) { pAssignTogetherExprPre.AddTerm(z[i][j][k][l], 1); pAssignTogetherExprAfter.AddTerm(z[i + 1][j][k][l], 1); } model.AddLe(pAssignTogetherExprPre, pAssignTogetherExprAfter, "AssignTogether"); } } } var2 = new IIntVar[1][][]; if (strAreaAggregation == _strSmallest) { IIntVar[][] w = new IIntVar[intCpgCount - 1][]; for (int i = 0; i < intCpgCount - 1; i++) { w[i] = model.BoolVarArray(intCpgCount); } var2[0] = w; //there is only one smallest patch will be involved in each aggregation step for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { var pOneSmallestExpr = model.LinearIntExpr(); for (int j = 0; j < intCpgCount; j++) { pOneSmallestExpr.AddTerm(w[i][j], 1); } model.AddEq(pOneSmallestExpr, 1.0, "OneSmallest"); } //forces that the aggregation must involve the smallest patch. for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { var pInvolveSmallestExpr = model.LinearIntExpr(); for (int k = 0; k < intCpgCount; k++) { if (j == k) //o != r { continue; } pInvolveSmallestExpr.AddTerm(y[i][j][j][k], 1); pInvolveSmallestExpr.AddTerm(y[i][k][k][j], 1); } model.AddLe(w[i][j], pInvolveSmallestExpr, "InvolveSmallest"); } } //To guarantee that patch $o$ is involved in aggregation is indeed the smallest patch double dblM = 1.1 * lscrg.dblArea; //a very large value for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { var aAreaExpr = ComputeAreaExpr(model, x[i], aCph); for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { if (j == k) //o != r { continue; } var pSumExpr = model.Sum(2.0, model.Negative(model.Sum(w[i][j], x[i][k][k]))); //(2-w_{t,o}-x_{t,r,r}) var pProdExpr = model.Prod(pSumExpr, dblM); //M(2-w_{t,o}-x_{t,r,r}) //A_{t,o}-A_{t,r}<= M(2-w_{t,o}-x_{t,r,r}) model.AddLe(model .Sum(aAreaExpr[j], model.Negative(aAreaExpr[k])), pProdExpr, "IndeedSmallest"); } } } } //***************compare with number of constraints counted manually************ rng = new IRange[1][]; rng[0] = new IRange[IRangeLt.Count]; for (int i = 0; i < IRangeLt.Count; i++) { rng[0][i] = IRangeLt[i]; } }