or-tools - add constraint to jobshop problem - or-tools

I would like to extend a bit the job shop example given here.
Given each machine has power consumption and at any given time (duration unit) there's a max power consumption on all machines, i would like to prevent overlap only if the sum of all machine consumptions passes a fixed value.
var allJobs =
new[] {
new[] {
// job0
new { machine = 0, duration = 3, power = 5 }, // task0
new { machine = 1, duration = 2, power = 2 }, // task1
new { machine = 2, duration = 2, power = 1 }, // task2
}.ToList(),
new[] {
// job1
new { machine = 0, duration = 2, power = 5 }, // task0
new { machine = 2, duration = 1, power = 2 }, // task1
new { machine = 1, duration = 4, power = 1}, // task2
}.ToList(),
new[] {
// job2
new { machine = 1, duration = 4, power = 1 }, // task0
new { machine = 2, duration = 3, power = 2 }, // task1
}.ToList(),
}.ToList();
The "flexible job job" example covers interval overlap but not the sum of a new variable and with the addon of this must be checked on every duration unit.
Any pointers on how i can achieve this?
Regards

For each task, create an interval. Use this interval in the no_overlap constraint of the corresponding machine.
Then add a cumulative constraint with the fixed value from the description as capacity.
Then for each task, add a demand (interval of the task, power of the task) to the cumulative constraint using this method: https://google.github.io/or-tools/dotnet/classGoogle_1_1OrTools_1_1Sat_1_1CumulativeConstraint.html#a922ab6a70999c054e9e94aa2dfb96be4

indeed that's the way to go.
i was able to implement it using your directions.
then i tryed to extend it a little further using the same method.
each machine, has a 'type', and and sum of power per 'type' could not exced a given value.
i grouped the intervals by type then call noOverlap on them.
But ive making a mistake somewhere as it aint correctly calculating despite give a solution.
//id, type
var machinesTypes = new[] {
1, 1, 2
};
var allJobs =
new[] {
new[] {
// job0
new { machine = 0, duration = 3, power = 5, type = 1 }, // task0
new { machine = 1, duration = 2, power = 4, type = 1 }, // task1
new { machine = 2, duration = 1, power = 2, type = 2 } , // task2
}.ToList()
}.ToList();
int numMachines = 0;
foreach (var job in allJobs)
{
foreach (var task in job)
{
numMachines = Math.Max(numMachines, 1 + task.machine);
}
}
int[] allMachines = Enumerable.Range(0, numMachines).ToArray();
// Computes horizon dynamically as the sum of all durations.
int horizon = 0;
foreach (var job in allJobs)
{
foreach (var task in job)
{
horizon += task.duration;
}
}
// Creates the model.
CpModel model = new CpModel();
//full power capacity Constraint
IntVar full_power_capacity = model.NewIntVar(0, 11, $"full_power_capacity");
CumulativeConstraint cc_full_power = model.AddCumulative(full_power_capacity);
//type power constraint
Dictionary<int, CumulativeConstraint> cc_all_machines = new Dictionary<int, CumulativeConstraint>();
foreach (int machine in allMachines)
{
int machineType = machinesTypes[allMachines[machine]];
if (!cc_all_machines.ContainsKey(machineType))
{
IntVar type_power_capacity = model.NewIntVar(0, 6, $"type_power_capacity_{machineType}");
CumulativeConstraint cc_type_power = model.AddCumulative(type_power_capacity);
cc_all_machines.Add(machineType, cc_type_power);
}
}
Dictionary<Tuple<int, int>, Tuple<IntVar, IntVar, IntervalVar>> allTasks = new Dictionary<Tuple<int, int>, Tuple<IntVar, IntVar, IntervalVar>>(); // (start, end, duration)
Dictionary<int, List<IntervalVar>> machineToIntervals = new Dictionary<int, List<IntervalVar>>();
Dictionary<int, List<IntervalVar>> machineTypesToIntervals = new Dictionary<int, List<IntervalVar>>();
for (int jobID = 0; jobID < allJobs.Count(); ++jobID)
{
var job = allJobs[jobID];
for (int taskID = 0; taskID < job.Count(); ++taskID)
{
var task = job[taskID];
String suffix = $"_{jobID}_{taskID}";
IntVar start = model.NewIntVar(0, horizon, "start" + suffix);
IntVar end = model.NewIntVar(0, horizon, "end" + suffix);
IntervalVar interval = model.NewIntervalVar(start, task.duration, end, "interval" + suffix);
var key = Tuple.Create(jobID, taskID);
allTasks[key] = Tuple.Create(start, end, interval);
if (!machineToIntervals.ContainsKey(task.machine))
{
machineToIntervals.Add(task.machine, new List<IntervalVar>());
}
machineToIntervals[task.machine].Add(interval);
cc_full_power.AddDemand(interval, task.power);
string suffix_2 = $"_{task.type}";
IntVar start_2 = model.NewIntVar(0, horizon, "start_2" + suffix_2);
IntVar end_2 = model.NewIntVar(0, horizon, "end_2" + suffix_2);
IntervalVar interval_2 = model.NewIntervalVar(start_2, task.duration, end_2, "interval_2" + suffix_2);
if (!machineTypesToIntervals.ContainsKey(task.type))
{
machineTypesToIntervals.Add(task.type, new List<IntervalVar>());
}
machineTypesToIntervals[task.type].Add(interval_2);
cc_all_machines[task.type].AddDemand(interval_2, task.power);
}
}
// Create and add disjunctive constraints.
foreach (int machine in allMachines)
{
model.AddNoOverlap(machineToIntervals[machine]);
}
foreach (var item in cc_all_machines)
{
model.AddNoOverlap(machineTypesToIntervals[item.Key]);
}
// Makespan objective.
IntVar objVar = model.NewIntVar(0, horizon, "makespan");
model.Minimize(objVar);
// Solve
CpSolver solver = new CpSolver();
CpSolverStatus status = solver.Solve(model);

Related

How can I make number counter to count multiple elements in Wix Velo

I'm making a website on Wix and it has Velo which works like javascript (I don't understand much in coding)
I was trying to do a number counter which counts from 0 to a given number and I did it, but I need 4 different counters not sure how to do it maybe someone can help, please.
so my code looks like this
$w.onReady(function() {});
let startNum = 0;
let endNum = 145;
const duration = 20;
$w.onReady(function() {
setInterval(() => {
countUp();
}, duration);
});
function countUp() {
if (startNum <= endNum) {
$w('#StartNumber').text = startNum.toString();
startNum++;
}
}
#startnumber is a text element that goes from 0 to 145
I want to do the same with 3 more elements #startnumber2, 3, and 4.
this is what I'm trying to do
The counting logic can be extracted to a function so you could call it for all the text components.
$w.onReady(function () {
count($w('#text1'), 0, 150, 1000);
count($w('#text2'), 0, 250, 1000);
count($w('#text3'), 0, 500, 1000);
count($w('#text4'), 0, 1000, 1000);
});
function count(obj, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
obj.text = `${Math.floor(progress * (end - start) + start)}`;
if (progress < 1) {
requestAnimationFrame(step);
}
};
requestAnimationFrame(step);
}
Demo: https://moshef9.wixsite.com/count-numbers
The counter function is taken from: https://stackoverflow.com/a/60291224/863110

Vehicle routing problem with dependent dimension constraints (Google ORTools)

I'm very new to OR-Tools and I'm trying to solve a modified VRP with capacity constraints from Google's guide.
In my problem vehicles transport multiple types of items. Some types can be transported together and others cannot.
What I tried
In the following code the types are A and B (they should not be transported together).
First I defined the two callbacks for demands and added the dimensions to the routing model
int demandACallbackIndex = routing.RegisterUnaryTransitCallback((long fromIndex) => {
var fromNode = manager.IndexToNode(fromIndex);
return demandsA[fromNode];
});
int demandBCallbackIndex = routing.RegisterUnaryTransitCallback((long fromIndex) => {
var fromNode = manager.IndexToNode(fromIndex);
return demandsB[fromNode];
});
routing.AddDimensionWithVehicleCapacity(demandACallbackIndex, 0,
capacitiesA,
true,
"CapacityA");
routing.AddDimensionWithVehicleCapacity(demandBCallbackIndex, 0,
capacitiesB,
true,
"CapacityB");
Then I retrieved the dimensions and added constraints to routing.solver() for every node
var capacityADimension = routing.GetDimensionOrDie("CapacityA");
var capacityBDimension = routing.GetDimensionOrDie("CapacityB");
for (int i = 0; i < noDeliveries; i++) {
var index = manager.NodeToIndex(i);
routing.solver().Add(capacityADimension.CumulVar(index) * capacityBDimension.CumulVar(index) == 0);
}
When I run the solver (with two vehicles) these constraints seem to be ignored (one vehicle remains parked while the other does all the work even though it shouldn't transport both types of items).
Is this even possible with OR-Tools? If yes, what did I do wrong?
Full code
public SimpleVehicleRoutingSolutionDto SolveVehicleRoutingWithItemConstraints(long[,] distances, long[] capacitiesA, long[] capacitiesB, long[] demandsA, long[] demandsB, int depot)
{
int noVehicles = capacitiesA.Length;
int noDeliveries = deliveriesA.Length;
RoutingIndexManager manager =
new RoutingIndexManager(noDeliveries, noVehicles, depot);
RoutingModel routing = new RoutingModel(manager);
int transitCallbackIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) => {
var fromNode = manager.IndexToNode(fromIndex);
var toNode = manager.IndexToNode(toIndex);
return distances[fromNode, toNode];
});
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
int demandACallbackIndex = routing.RegisterUnaryTransitCallback((long fromIndex) => {
// Convert from routing variable Index to demand NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
return demandsA[fromNode];
});
int demandBCallbackIndex = routing.RegisterUnaryTransitCallback((long fromIndex) => {
// Convert from routing variable Index to demand NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
return demandsB[fromNode];
});
routing.AddDimensionWithVehicleCapacity(demandACallbackIndex, 0,
capacitiesA,
true,
"CapacityA");
routing.AddDimensionWithVehicleCapacity(demandBCallbackIndex, 0,
capacitiesB,
true,
"CapacityB");
var capacityADimension = routing.GetDimensionOrDie("CapacityA");
var capacityBDimension = routing.GetDimensionOrDie("CapacityB");
for (int i = 0; i < noDeliveries; i++) {
var index = manager.NodeToIndex(i);
routing.solver().Add(capacityADimension.CumulVar(index) * capacityBDimension.CumulVar(index) == 0);
}
RoutingSearchParameters searchParameters =
operations_research_constraint_solver.DefaultRoutingSearchParameters();
searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.GuidedLocalSearch;
searchParameters.TimeLimit = new Duration { Seconds = 1 };
Assignment solution = routing.SolveWithParameters(searchParameters);
var ret = new SimpleVehicleRoutingSolutionDto();
long totalDistance = 0;
for (int i = 0; i < noVehicles; ++i)
{
var vecihle = new VehiclePathDto { Index = i };
long routeDistance = 0;
var index = routing.Start(i);
while (routing.IsEnd(index) == false)
{
long nodeIndex = manager.IndexToNode(index);
vecihle.Waypoints.Add(new WaypointDto { Index = nodeIndex });
var previousIndex = index;
index = solution.Value(routing.NextVar(index));
routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0);
}
vecihle.Distance = routeDistance;
ret.Vehicles.Add(vecihle);
totalDistance += routeDistance;
}
ret.TotalDistance = totalDistance;
return ret;
}
And the input:
long[,] dist = {
{ 0, 5, 6 },
{ 5, 0, 3 },
{ 6, 3, 0 }
};
long[] capA = { 5, 5 };
long[] capB = { 5, 5 };
long[] demA = { 0, 1, 0 };
long[] demB = { 0, 0, 1 };
var routingSolution = vehicleRouting.SolveVehicleRoutingWithItemConstraints(dist, capA, capB, demA, demB, 0);
I fixed the problem.
The issue was that the number of nodes was 3 (noDeliveries), however the number of indices was 6, so I only set the constraint on half of them.
Fixed code:
for (int i = 0; i < manager.GetNumberOfIndices(); i++) {
routing.solver().Add(capacityADimension.CumulVar(i) * capacityBDimension.CumulVar(i) == 0);
}
EDIT:
Even better if constraints are set only for the route end node, since the CumulVar value is strictly increasing.
for (int j = 0; j < noVehicles; j++) {
var index = routing.End(j);
routing.solver().Add(capacityADimension.CumulVar(index) * capacityBDimension.CumulVar(index) == 0);
}

Creating calendar syncronised to spreadsheet but all events are created onn 1 Jan 1970 at 03:00. What did I miss?

I am following the conversation and tutorial in post Create Google Calendar Events from Spreadsheet but prevent duplicates
But I cannot get the final solution to work. It fills my calendar but all dates are 1/1/1970 at 3 am.
The code is as follows:
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name: "Export Events",
functionName: "exportEvents"
}];
sheet.addMenu("Calendar Actions", entries);
};
function parseDate(s) {
var months = {
jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5, jul: 6, aug: 7, sep: 8, oct: 9, nov: 10, dec: 11
};
var p = s.replace(".", "").split('-');
return new Date(p[2], p[1], p[0]);
}
/**
* Export events from spreadsheet to calendar
*/
function exportEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 1; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getDisplayValues();
var calId = "the calendar"; // PRODUCTION
//var calId = "the calendar; // TEST
var cal = CalendarApp.getCalendarById(calId);
//Logger.log(cal);
//Logger.log(data.length);
for (i = 0; i<data.length; i++) {
if (i<headerRows) continue; // Skip header row(s)
if (data[i][0].length<1) continue; // Skip if no content.
var row = data[i];
Logger.log(row);
var date = parseDate(row[0]); // First column
//Logger.log(date);
var title = row[1]; // Second column
var tstart = new Date();
var s = row[2].split(":");
tstart.setHours(s[0]);
tstart.setMinutes(s[1]);
tstart.setSeconds(s[2]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date();
var e = row[3].split(":");
tstop.setHours(e[0]);
tstop.setMinutes(e[1]);
tstop.setSeconds(e[2]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var loc = row[4];
var desc = row[5];
var id = row[6]; // Sixth column == eventId
// Check if event already exists, update it if it does
var event = null;
if (id.length > 0) {
try {
event = cal.getEventSeriesById(id);
} catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
var newEvent = cal.createEvent(title, tstart, tstop, {
description: desc, location: loc
}).getId();
var r = i + 1;
var cell = sheet.getRange("G" + r);
cell.setValue(newEvent);
} else {
Logger.log(event);
event.setTitle(title);
event.setDescription(desc);
event.setLocation(loc);
// event.setTime(tstart, tstop); // cannot setTime on eventSeries.
// ... but we CAN set recurrence!
var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
event.setRecurrence(recurrence, tstart, tstop);
}
debugger;
}
}
I think I must be making an obvious rookie mistake but cannot figure it out. Any chance of some help?
BTW: my dates are formatted: 12/01/2019 and times formatted: 18:00:00.

Trying to create a dynamic Dundas Stackedarea chart

Good afternoon. I try to research and have yet to find anyone that has an example of this, I normally do not ask for help, I just figure it out, but this one is killing me! I am trying to create a stacked area chart dynamically, I already can create a dynamic area chart, but cannot for the life of me figure out how to get a stacked area chart to stack the series. I have made something similar in excel and I can get it to chart fine, but it is not dynamic.
I have data that is laid out like this:
How the data is laid out
And this is how I want the chart to look:
How I want the chart to look
How can I associate the data to categories or whatever it is I need to do? I have the data in an array but I can just not seem to figure out how to get the chart to stack. Can anyone help? If you need some more info please ask, I know I am not including my code, mainly because it is very ugly and drawn out, but can try to compress it a bit and simplify if anyone needs that.
My code is below (maybe that will help, even if it is ugly)
For tmpatozgroup = 1 To 1
Dim chart1 As New Chart()
chart1.ID = "chrt-" & tmpatozgroup & "-" & atozser
Dim seriesperrow As Integer
Dim chartArea1 As New ChartArea()
chart1.Height = 340
chart1.Palette = ChartColorPalette.Dundas
chart1.BackColor = System.Drawing.Color.LightGray
chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss
chart1.BorderLineColor = System.Drawing.Color.Gray
chart1.BorderLineStyle = ChartDashStyle.Solid
chart1.BorderLineWidth = 4
' Set the ChartArea properties
chartArea1.Name = "Default"
chartArea1.BackColor = System.Drawing.Color.LightGray
chartArea1.AxisX.LabelsAutoFit = False
chartArea1.AxisX.LabelStyle.FontAngle = -45
chartArea1.Area3DStyle.Enable3D = True
chart1.ChartAreas.Add(chartArea1)
Dim series1 As New Series()
series1.Name = tblGrouping1(tmpatozgroup, 0)
chart1.Series.Add(series1)
chart1.Legends.Clear()
If Not IsNothing(tblGrouping1(tmpatozgroup, 0)) Then
For tmpatozgroup2 = 1 To 9
Dim legend1 As New Legend()
Dim sername As String
Dim servalues() As Double
Dim serformat As String
Dim chrtSeriesCnt As Integer
sername = tblGrouping1(0, tmpatozgroup2)
'need to tear the current row out of the array and place in tmpseries
Dim tmpatozcnt As Integer
For tmpatozcnt = 1 To 999
If IsNothing(tblGrouping1(0, tmpatozcnt)) Then atozseries = tmpatozcnt : Exit For
tmpSeries(tmpatozcnt) = tblGrouping1(tmpatozgroup2, tmpatozcnt)
chrtSeriesLabels(tmpatozcnt) = tblGrouping1(0, tmpatozcnt)
Next
servalues = tmpSeries
serformat = chrtSeriesForm1
chart1.Width = 1000
seriesperrow = 1
'chart1.AlignDataPointsByAxisLabel()
series1.Type = SeriesChartType.StackedColumn
series1("StackedGroupName") = "'" & tblGrouping1(tmpatozgroup, 0) & "'"
If Not IsNothing(tblGrouping1(tmpatozgroup, 0)) Then
For Each ser As Series In chart1.Series
For i2 As Integer = 1 To atozseries - 1
ser.Points.AddXY(chrtSeriesLabels(i2), servalues(i2 - 1))
ser.Points(i2 - 1).BorderColor = Drawing.Color.FromArgb(Split(sercolor(i2), "|")(0), Split(sercolor(i2), "|")(1), Split(sercolor(i2), "|")(2))
ser.Points(i2 - 1).Color = Drawing.Color.FromArgb(Split(sercolor(i2), "|")(0), Split(sercolor(i2), "|")(1), Split(sercolor(i2), "|")(2))
'ser.XAxisType = AxisType.Secondary
Dim tooltipformat As String
If serformat = "Currency" Then serformat = "$#,##0.00" : tooltipformat = "{$#,#.00}"
If serformat = "###,###,##0.00" Then serformat = "#,##0.00" : tooltipformat = "{#,#}"
If serformat = "###,###,##0" Then serformat = "0" : tooltipformat = "{#,#}"
ser.Points(i2 - 1).ToolTip = ser.Points(i2 - 1).AxisLabel & " : #VALY" & tooltipformat
Next
chart1.ChartAreas(0).AxisX.Interval = 1
chart1.ChartAreas(0).AxisX.LabelStyle.Interval = 1
chart1.ChartAreas(0).AxisX.Title = "test" 'chrtXAxisName
chart1.ChartAreas(0).AxisY.Title = sername
chart1.ChartAreas(0).AxisY.LabelStyle.Format = serformat
chart1.Palette = ChartColorPalette.Dundas
Next
End If
Next
If seriesonrow = seriesperrow Or seriesonrow = 0 Then
tr = New TableRow
tr.CssClass = "charts column"
tr.Style("display") = "none"
End If
td = New TableCell
td.HorizontalAlign = HorizontalAlign.Center
td.ColumnSpan = 6 / seriesperrow
td.Controls.Add(chart1)
tr.Cells.Add(td)
tblReport.Rows.Add(tr)
chart1 = Nothing
End If
Next
Thanks a bunch in advance!
Later
Here's a sample:
<asp:Chart ID="Chart1" runat="server" Width="600px">
<Series>
<asp:Series Name="Series1" ChartType="StackedArea">
<Points>
<asp:DataPoint XValue="1" YValues="10" />
<asp:DataPoint XValue="2" YValues="20" />
<asp:DataPoint XValue="3" YValues="30" />
<asp:DataPoint XValue="4" YValues="15" />
</Points>
</asp:Series>
<asp:Series ChartArea="ChartArea1" ChartType="StackedArea" Name="Series2">
<Points>
<asp:DataPoint XValue="1" YValues="20" />
<asp:DataPoint XValue="2" YValues="40" />
<asp:DataPoint XValue="3" YValues="60" />
<asp:DataPoint XValue="4" YValues="45" />
</Points>
</asp:Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1">
<AxisY>
<MajorGrid LineColor="DarkGray" LineDashStyle="Dot" />
</AxisY>
<AxisX>
<MajorGrid LineColor="DarkGray" LineDashStyle="Dot" />
</AxisX>
</asp:ChartArea>
</ChartAreas>
</asp:Chart>
EDIT: Using code-behind:
protected void Page_Load(object sender, EventArgs e)
{
Chart chart1 = new Chart();
ChartArea area1 = new ChartArea("Area1");
Series series1 = new Series();
series1.ChartType = SeriesChartType.StackedArea;
series1.Points.Add(new DataPoint { XValue = 1, YValues = new double[] { 10 } });
series1.Points.Add(new DataPoint { XValue = 2, YValues = new double[] { 20 } });
series1.Points.Add(new DataPoint { XValue = 3, YValues = new double[] { 30 } });
series1.Points.Add(new DataPoint { XValue = 4, YValues = new double[] { 15 } });
series1.ChartArea = "Area1";
Series series2 = new Series();
series2.ChartType = SeriesChartType.StackedArea;
series2.Points.Add(new DataPoint { XValue = 1, YValues = new double[] { 20 } });
series2.Points.Add(new DataPoint { XValue = 2, YValues = new double[] { 40 } });
series2.Points.Add(new DataPoint { XValue = 3, YValues = new double[] { 60 } });
series2.Points.Add(new DataPoint { XValue = 4, YValues = new double[] { 45 } });
series2.ChartArea = "Area1";
chart1.ChartAreas.Add(area1);
chart1.Series.Add(series1);
chart1.Series.Add(series2);
Controls.Add(chart1);
}
EDIT 2: adding a legend:
protected void Page_Load(object sender, EventArgs e)
{
Chart chart1 = new Chart();
ChartArea area1 = new ChartArea("Area1");
Legend legend1 = new Legend("Legend1");
legend1.Docking = Docking.Top;
legend1.Alignment = System.Drawing.StringAlignment.Center;
Series series1 = new Series("Bought");
series1.ChartType = SeriesChartType.StackedArea;
series1.Points.Add(new DataPoint { XValue = 1, YValues = new double[] { 10 } });
series1.Points.Add(new DataPoint { XValue = 2, YValues = new double[] { 20 } });
series1.Points.Add(new DataPoint { XValue = 3, YValues = new double[] { 30 } });
series1.Points.Add(new DataPoint { XValue = 4, YValues = new double[] { 15 } });
series1.ChartArea = "Area1";
series1.Legend = "Legend1";
Series series2 = new Series("Sold");
series2.ChartType = SeriesChartType.StackedArea;
series2.Points.Add(new DataPoint { XValue = 1, YValues = new double[] { 20 } });
series2.Points.Add(new DataPoint { XValue = 2, YValues = new double[] { 40 } });
series2.Points.Add(new DataPoint { XValue = 3, YValues = new double[] { 60 } });
series2.Points.Add(new DataPoint { XValue = 4, YValues = new double[] { 45 } });
series2.ChartArea = "Area1";
series2.Legend = "Legend1";
chart1.ChartAreas.Add(area1);
chart1.Legends.Add(legend1);
chart1.Series.Add(series1);
chart1.Series.Add(series2);
Controls.Add(chart1);
}

Quickbooks CustomerQuery with Iterator returning duplicate records

I have a strange issue, and I am not sure where the error is
I am working on C#, and while running a query with filters against the Customer object, I get a strange series of results
If the filter I set should return 8 records, then my implementation returns 8, 8, 3, 1, 1, 1 records (in that order, in every subsequent call, and all those are duplicate)...
This is how I implemented the Iterator
var customerQuery = new CustomerQuery()
{
ChunkSize = "8",
Item = Guid.NewGuid().ToString("N"),
IncludeFinancialIndicator = false,
IncludeFinancialIndicatorSpecified = true,
MinimumBalanceSpecified = true,
MinimumBalance = 92,
SynchronizedFilterSpecified = true,
SynchronizedFilter = SynchronizedFilterEnumType.Synchronized,
};
var results = new List<Customer>();
int count;
//Loop until find all the results.
do
{
IEnumerable<Customer> partialResult = customerQuery.ExecuteQuery<Customer>(context);
count = partialResult.Count();
//First pass here returns 8 records
//Second pass returns same 8 records again
//third pass returns 3 records
//Three more passes with 1 record each
results.AddRange(partialResult);
} while (count > 0);
Am I doing something wrong or missing anything?
Thanks!
Edit:
this is the code implementing the Paging option....
var customerSet = new List<Customer>();
List<Customer> customerQueryResult = null;
int startPage = 1;
var qbdCustomerQuery = new CustomerQuery();
do
{
qbdCustomerQuery.ChunkSize = "10";
qbdCustomerQuery.MinimumBalanceSpecified = true;
qbdCustomerQuery.MinimumBalance = 92;
qbdCustomerQuery.ItemElementName = ItemChoiceType4.StartPage;
qbdCustomerQuery.Item = startPage.ToString();
customerQueryResult = qbdCustomerQuery.ExecuteQuery<Customer>(context).ToList();
if (customerQueryResult.Count > 0) { customerSet.AddRange(customerQueryResult); }
startPage++;
} while (customerQueryResult.Count > 0);
If I set ChunkSize to "100" I get the 8 expected records, but when trying to run it with ChunkSize = "10" I get 8,8,1 (duplicate records)