Re: [or-tools-discuss] AttributeError: 'list' object has no attribute 'GetIntegerVarValueMap'

425 views
Skip to first unread message
Message has been deleted

Laurent Perron

unread,
Dec 13, 2023, 7:54:13 AM12/13/23
to or-tools...@googlegroups.com
Too vague.

I cannot run your code as the data files are not included, and you do not specify the line where it fails.

Most likely you are passing a list where the solver expects an expression (x + y).

About speed, there is not much we can do. There is some pandas support, not sure it is fully optimized.
Laurent Perron | Operations Research | lpe...@google.com | (33) 1 42 68 53 00



Le mer. 13 déc. 2023 à 13:16, Julius Günther <juli...@outlook.de> a écrit :
I try to add batch sizes to the single-machine scheduling model.
I get the AttributeError: 'list' object has no attribute 'GetIntegerVarValueMap'.
What does that mean and how can I fix that?

Except for that, do you have suggestions on how to add variable Batch-sizes efficiently?

import pandas as pd
import openpyxl
from typing import Sequence
import collections
from absl import app
from absl import flags
from google.protobuf import text_format
from ortools.sat.python import cp_model

# Einlesen der Daten ---------------------------------------------------------------------------------------
excel_path = "C:\\Users\\juliu\\Nextcloud\\0_DPL_Guenther_Julius\\Praxisphase\\Eingabedatei.xlsx"
excel_path_2 = "C:\\Users\\juliu\\Nextcloud\\0_DPL_Guenther_Julius\\Praxisphase\\Ausgabedatei.xlsx"

sheet_name_import = "Daten uc4"

df1 = pd.read_excel(excel_path, sheet_name_import, header = None, usecols = "C:J", skiprows = 14, nrows = 8)
df2 = pd.read_excel(excel_path, sheet_name_import, header = None)

weekly_demand = df2.iloc[2, 2:10].astype(str).replace(("'"),("")).astype(int).tolist()

min_batch_size = df2.iloc[4, 2:10].astype(str).replace(("'"),("")).astype(int).tolist()

cycle_times = df2.iloc[10, 2:10].astype(str).replace(("'"),("")).astype(int).tolist()

setup_times = [[30]*len(weekly_demand)] # Start-Job (Dummy)
setup_times_no_dummy = df1.values.astype(int).tolist()
for element in setup_times_no_dummy:
    setup_times.append(element)

due_dates = df2.iloc[8, 2:10].astype(str).replace(("'"),("")).astype(int).tolist()
due_dates = [element *8*60 for element in due_dates]

release_dates = df2.iloc[9, 2:10].astype(str).replace(("'"),("")).astype(int).tolist()
release_dates = [element *8*60 for element in release_dates]

priorities = df2.iloc[11, 2:10].astype(str).tolist()

print(setup_times)
print(weekly_demand)
print(min_batch_size)
print(due_dates)
print(release_dates)
print(priorities)

# Verarbeiten der Daten-------------------------------------------------------------------------
min_durations = [a // b for a, b in zip(min_batch_size, cycle_times)]
max_durations = [a // b for a, b in zip(weekly_demand, cycle_times)]
num_jobs = [a // b for a, b in zip(weekly_demand, min_batch_size)]
job_durations = [[a] * b for a, b in zip(min_durations, num_jobs)]

num_jobs = len(job_durations)
all_jobs = range(num_jobs)

# Erstellen von Befehlszeilenargumenten -----------------------------------------------
_OUTPUT_PROTO = flags.DEFINE_string(
    "output_proto", "", "Output file to write the cp_model proto to."
)
_PARAMS = flags.DEFINE_string(
    "params",
    "log_search_progress:true",
    "Sat solver parameters.",
)
_PREPROCESS = flags.DEFINE_bool(
    "--preprocess_times", True, "Preprocess setup times and durations"
)

# Konfiguration der Lösungsausgabe ----------------------------------------------------
class SolutionPrinter(cp_model.CpSolverSolutionCallback):
    def __init__(self):
        cp_model.CpSolverSolutionCallback.__init__(self)
        self.__solution_count = 0
       
    def on_solution_callback(self):
        print(
            "Solution %i, time = %f s, objective = %i"
            % (self.__solution_count, self.WallTime(), self.ObjectiveValue())
        )
               
        self.__solution_count += 1

# Erstellen von Lösungsfunktion -----------------------------------------------------
def single_machine_scheduling():
   
    parameters = _PARAMS.value
    output_proto_file = _OUTPUT_PROTO.value
   
    # Erstellen des Lösungsmodells -------------------------------------------------
    model = cp_model.CpModel()
   
    # Festlegen des Horizonts ------------------------------------------------------
    horizon = sum(max_durations) + sum(
        max(setup_times[i][j] for i in range(num_jobs + 1)) for j in range(num_jobs)
    )
   
    print("Greedy horizon =", horizon)

    intervals = []
    starts = []
    ends = []

    # Erstellen der Variablen für jeden Job ----------------------------------------
    for job_id in all_jobs:
        product_start = []
        product_end = []
        for batch in range(max(len(zeile) for zeile in job_durations)):
            duration = job_durations[job_id][batch]
            release_date = release_dates[job_id]
            due_date = due_dates[job_id]
            print(
                "job %2i: start = %5i, duration = %4i, end = %6i"
                % (job_id, release_date, duration, due_date)
            )
            name_suffix = "_%i_%i" % (job_id, batch)
            start = model.NewIntVar(release_date, due_date, "s" + name_suffix)
            end = model.NewIntVar(release_date, due_date, "e" + name_suffix)
            interval = model.NewIntervalVar(start, duration, end, "i" + name_suffix)
            product_start.append(start)
            product_end.append(end)
            intervals.append(interval)
        starts.append(product_start)
        ends.append(product_end)
       
    print(starts)
    # Erstellen von Überlappungs-Constraint -----------------------------------------
    model.AddNoOverlap(intervals)

    # Erstellen von Verbindungen aller Jobs der Rüstmatrix --------------------------
    arcs = []
    for i in all_jobs:
        min_start_time = max(release_dates[i], setup_times[0][i])
        for batch in range(max(len(zeile) for zeile in job_durations)):
            start_lit = model.NewBoolVar("")
            arcs.append((0, batch + 1, start_lit))
            model.Add(starts[i][batch] == min_start_time).OnlyEnforceIf(start_lit)
            arcs.append((batch + 1, 0, model.NewBoolVar("")))
           
            for j in all_jobs:
                for batch2 in range(max(len(zeile) for zeile in job_durations)):
                    if i == j & batch == batch2:
                        continue
                    lit = model.NewBoolVar("%i_%i follows %i_%i" % (j, batch, i, batch2))
                    arcs.append((batch + 1, batch2 + 1, lit))
           
                    model.Add(starts[j][batch2] >= ends[i][batch] + setup_times[i + 1][j]).OnlyEnforceIf(lit)
                   
    # Erstellen von Verbindungs-Constraint -----------------------------------------
    model.AddCircuit(arcs)

    # Erstellen der Zeilfunktion ---------------------------------------------------
    makespan = model.NewIntVar(0, horizon, "makespan")
    model.AddMaxEquality(makespan, ends)
    model.Minimize(makespan)

    if output_proto_file:
        print("Writing proto to %s" % output_proto_file)
        with open(output_proto_file, "w") as text_file:
            text_file.write(str(model))

    # Erstellen des Solvers --------------------------------------------------------
    solver = cp_model.CpSolver()
    if parameters:
        text_format.Parse(parameters, solver.parameters)
       
    solution_printer = SolutionPrinter()
    # Übergabe des Modells an den Solver -------------------------------------------
    solver.Solve(model, solution_printer)
   
    for job_id in all_jobs:
        for batch in range(max(len(zeile) for zeile in job_durations)):
            print(
                "job %i_%i starts at %i end ends at %i"
                % (job_id + 1, batch + 1, solver.Value(starts[job_id][batch]), solver.Value(ends[job_id][batch]))
            )
       
# Erstellen der Hauptfunktion -----------------------------------------------------
def main(argv: Sequence[str]) -> None:
    if len(argv) > 1:
        raise app.UsageError("Too many command-line arguments.")
   
    single_machine_scheduling()

if __name__ == "__main__":
    app.run(main)

--
You received this message because you are subscribed to the Google Groups "or-tools-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to or-tools-discu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/or-tools-discuss/a0421290-4bf3-4304-8b4a-e3d871876279n%40googlegroups.com.
Message has been deleted

Laurent Perron

unread,
Dec 13, 2023, 8:07:38 AM12/13/23
to or-tools...@googlegroups.com

No, which line in your code. My case works, it just receive a wrong argument


Le mer. 13 déc. 2023, 14:05, Julius Günther <juli...@outlook.de> a écrit :
I'm Sorry, here is the code with the data files.
The code fails in the cp_model file:
  File "C:\Users\juliu\AppData\Roaming\Python\Python311\site-packages\ortools\sat\python\cp_model.py", line 2326, in ParseLinearExpression
    coeffs_map, constant = cast(LinearExpr, linear_expr).GetIntegerVarValueMap()
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

AttributeError: 'list' object has no attribute 'GetIntegerVarValueMap'
import pandas as pd
import openpyxl
from typing import Sequence
import collections
from absl import app
from absl import flags
from google.protobuf import text_format
from ortools.sat.python import cp_model

weekly_demand = [1250000, 1500000, 1250000, 2000000, 1000000, 750000, 2000000, 750000]
min_batch_size = [250000, 300000, 250000, 400000, 200000, 150000, 400000, 150000]
cycle_times = [10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]

setup_times = [[30, 30, 30, 30, 30, 30, 30, 30],
               [0, 45, 30, 35, 40, 25, 30, 35],
               [40, 0, 30, 45, 20, 50, 25, 30],
               [30, 35, 0, 20, 30, 40, 30, 30],
               [30, 25, 30, 0, 35, 25, 35, 40],
               [25, 20, 35, 30, 0, 40, 45, 35],
               [35, 25, 20, 35, 30, 0, 40, 35],
               [30, 20, 15, 20, 30, 40, 0, 25],
               [50, 25, 30, 25, 20, 35, 30, 0]]

due_dates = [2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400]
release_dates = [0, 0, 0, 0, 0, 0, 0, 0]
Message has been deleted

Laurent Perron

unread,
Dec 13, 2023, 8:23:18 AM12/13/23
to or-tools...@googlegroups.com
of course :-(

Laurent Perron | Operations Research | lpe...@google.com | (33) 1 42 68 53 00



Le mer. 13 déc. 2023 à 14:17, Julius Günther <juli...@outlook.de> a écrit :
I guess it's in this line:     model.AddMaxEquality(makespan, ends)
I think because ends is a 2D List?
Message has been deleted
Message has been deleted

Laurent Perron

unread,
Dec 13, 2023, 9:53:13 AM12/13/23
to or-tools...@googlegroups.com
  model.Add(starts[i][batch] == min_start_time).OnlyEnforceIf(start_lit)

Risky: are you sure no job will still be active on that machine at min_start_time ? I would use >=

For batches, you do not impose an order ? batch1 before batch2...


Le mer. 13 déc. 2023 à 15:11, Julius Günther <juli...@outlook.de> a écrit :
Another Question:
When I model the arcs, I still connect Jobs with themselves: Circuit/Route constraint contains multiple self-loop involving node 1
I thought I fixed it with the if function?

    arcs = []
    for i in all_jobs:
        min_start_time = setup_times[0][i]
        for batch in range(max(len(zeile) for zeile in job_durations)):
            start_lit = model.NewBoolVar("")
            arcs.append((0, batch + 1, start_lit))
            model.Add(starts[i][batch] == min_start_time).OnlyEnforceIf(start_lit)
            arcs.append((batch + 1, 0, model.NewBoolVar("")))
           
            for j in all_jobs:
                for batch2 in range(max(len(zeile) for zeile in job_durations)):
                    if i == j and batch == batch2:
                        continue
                    lit = model.NewBoolVar("%i_%i follows %i_%i" % (j, batch, i, batch2))
                    arcs.append((batch + 1, batch2 + 1, lit))
           
                    model.Add(starts[j][batch2] >= ends[i][batch] + setup_times[i + 1][j]).OnlyEnforceIf(lit)

Julius Günther schrieb am Mittwoch, 13. Dezember 2023 um 14:27:23 UTC+1:
Sorry my fault. 
Code still doesn't work, but thanks.


--
--Laurent

Reply all
Reply to author
Forward
0 new messages