I've been struggIing to make a 2d Stock cutting solution. I found a Python code that is proven to work and converted it to C#. I get results ofthe X1 values but the Y values are always 0. I checked the log and its really difficult for me to understand this type of programming. Can anyone please help me. The original code is here in the comments https://yetanothermathprogrammingconsultant.blogspot.com/2021/02/2d-bin-packing-with-google-or-tools-cp.html
List<advRectangle> smallRectangles = new() { };
smallRectangles.Add(new advRectangle(500, 750, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 500, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 1000, 0, 0, "1"));
smallRectangles.Add(new advRectangle(2000, 500, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 752, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 2000, 0, 0, "1"));
smallRectangles.Add(new advRectangle(500, 750, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 500, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1250, 250, 0, 0, "1"));
smallRectangles.Add(new advRectangle(250, 500, 0, 0, "1"));
smallRectangles.Add(new advRectangle(500, 750, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 500, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 1000, 0, 0, "1"));
smallRectangles.Add(new advRectangle(2000, 500, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 750, 0, 0, "1"));
smallRectangles.Add(new advRectangle(1000, 2000, 0, 0, "1"));
advRectangle BigRect = new advRectangle(2000, 3000, 0, 0, "1");
// Create a CP model
CpModel model = new CpModel();
// Data
int H = Convert.ToInt32(BigRect.UHeight()); // Bin height
int W = Convert.ToInt32(BigRect.UWidth()); ; // Bin width
List<int> h = smallRectangles.Select(sr => Convert.ToInt32(sr.UHeight())).ToList();
List<int> w = smallRectangles.Select(sr => Convert.ToInt32(sr.UWidth())).ToList();
int n = h.Count; // Number of items
int m = 10; // Max number of bins
// Variables
IntVar[] x1 = new IntVar[n];
IntVar[] x2 = new IntVar[n];
IntVar[] y1 = new IntVar[n];
IntVar[] y2 = new IntVar[n];
// Constraints
long[][] x1Intervals = new long[n][];
long[][] x2Intervals = new long[n][];
for (int i = 0; i < n; i++)
{
List <long[]> tempx1 = new List<long[]>();
for (int j = 0; j < m; j++)
{
tempx1.Add(new long[] { j * W, (j+1)*W - w[i] });
}
x1Intervals = tempx1.ToArray();
x1[i] = model.NewIntVarFromDomain(Google.OrTools.Util.Domain.FromIntervals(x1Intervals), $"x1[{i}]");
}
for (int i = 0; i < n; i++)
{
List<long[]> tempx2 = new List<long[]>();
for (int j = 0; j < m; j++)
{
tempx2.Add(new long[] { j * W + w[i], (j + 1) * W });
}
x2Intervals = tempx2.ToArray();
x2[i] = model.NewIntVarFromDomain(Google.OrTools.Util.Domain.FromIntervals(x2Intervals), $"x2[{i}]");
}
for (int i = 0; i < n; i++)
{
y1[i] = model.NewIntVar(0, H - h[i], $"y1[{i}]");
}
for (int i = 0; i < n; i++)
{
y2[i] = model.NewIntVar(h[i], H, $"y2[{i}]");
}
// Define literals for bin assignment
BoolVar[][] lit = new BoolVar[n][];
for (int i = 0; i < n; i++)
{
lit[i] = new BoolVar[m];
for (int j = 0; j < m; j++)
{
lit[i][j] = model.NewBoolVar($"lit[{i}][{j}]");
}
}
// Now we assert that every rectangle belongs to exactly one bin.Also we must refine left and right boundaries of every rectangle:
var bv1 = new List<BoolVar>();
var lv1 = new List<long>();
var bv2 = new List<BoolVar>();
var lv2 = new List<long>();
var bvy1 = new List<BoolVar>();
var lvy1 = new List<long>();
var bvy2 = new List<BoolVar>();
var lvy2 = new List<long>();
for (int i = 0; i < n; i++)
{
model.Add(Google.OrTools.Sat.LinearExpr.Sum(lit[i]) == 1);
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
bv1.Add(lit[i][j]);
lv1.Add(j * W);
}
for (int j = 0; j < m; j++)
{
bv2.Add(lit[i][j]);
lv2.Add((j + 1) * W);
}
}
for (int i = 0; i < n; i++)
{
model.Add(Google.OrTools.Sat.LinearExpr.WeightedSum(bv1, lv1) <= x1[i]);
model.Add(Google.OrTools.Sat.LinearExpr.WeightedSum(bv2, lv2) >= x2[i]);
}
// Define interval variables
Google.OrTools.Sat.IntervalVar[] x_interval = new Google.OrTools.Sat.IntervalVar[n];
Google.OrTools.Sat.IntervalVar[] y_interval = new Google.OrTools.Sat.IntervalVar[n];
for (int i = 0; i < n; i++)
{
x_interval[i] = model.NewIntervalVar(x1[i], w[i], x2[i], "");
y_interval[i] = model.NewIntervalVar(y1[i], h[i], y2[i], "");
}
//fixed
NoOverlap2dConstraint NoOverlap2Constraint = new
NoOverlap2dConstraint(model.Model);
NoOverlap2Constraint.Proto = model.AddNoOverlap2D().Proto;
for (int i = 0; i < n; i++)
{ NoOverlap2Constraint.AddRectangle(x_interval[i], y_interval[i]);}
// Define the objective
IntVar obj = model.NewIntVar(0, m, "obj");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
model.Add(obj >= (j + 1)).OnlyEnforceIf(lit[i][j]);
}
}
model.Minimize(obj);
// Create a CP solver.
CpSolver solver = new CpSolver();
solver.StringParameters = "log_search_progress:true";
solver.SetLogCallback(LogCallback);
// Solve the problem
CpSolverStatus status = solver.Solve(model);
if (status == CpSolverStatus.Optimal)
{
// Print the bin and position of each item
for (int i = 0; i < n; i++)
{
smallRectangles[i].X = solver.Value(x1[i]);
smallRectangles[i].Y = solver.Value(y1[i]);
Console.WriteLine($"Item {i}: Bin {solver.Value(obj)}, X1: {solver.Value(x1[i])}, Y1: {solver.Value(y1[i])}");
}
}
else
{
MessageBox.Show("No optimal solution found.");
}
;
as with your last entry, you create one no_overlap_2d constraint per rectangle. Therefore each constraint is constraining 1 rectangle, and thus has nothing to do.
You need to create one no_overlap_2d constraint and add all rectangles to the same constraint.