2XCL
2XCL

Reputation: 1

Gurobi Pool Search Mode outputs same Solutions multiple times

I am currently working on lineplanning problems (linear progamming), f.e. described in https://www.researchgate.net/publication/225218930_Models_for_Line_Planning_in_Public_Transport.

I tried to implement a version that creates a (weightend) sum of direct travlers and costs in Python and tried to solve it via Gurobi. For further applications I want to check all feasable solutions for this problem via Gurobi Pool Search: https://www.gurobi.com/documentation/current/refman/poolsearchmode.html. The code solves the optimal solution and also gives out the correct line plan, but doesnt find all feasable solutions and their respective combined_obj values and rather outputs same solutions multiple times. I am not sure how easy it is to understand the code and/or find the mistake here.

This is my code:

if __name__ == '__main__':
    if len(sys.argv) < 2:
        raise ConfigNoFileNameGivenException()
    logger.info("Start reading configuration")
    config = ConfigReader.read(sys.argv[1])
    #parameters = SolverParameters(config, "lc_")
    parameters = DirectParameters(config)

    logger.info("Finished reading configuration")

    logger.info("Begin reading input data")
    ptn = PTNReader.read(read_loads=True)
    od = DictOD()
    #od = ODReader.read(od)


    ods = ODReader.readMultiple(od)
    logger.info(f"Read in {len(ods)} OD matrices")
    logger.info("Finished reading input data")

    for index_of_od_matrix,od in enumerate(ods):


        logger.info(f"Begin execution of robust multicrieteria line planning model for OD-Matrix {index_of_od_matrix}")
        line_pool = LineReader.read(ptn, read_frequencies=False)
        solver = Solver.createSolver(parameters.getSolverType())
        model = solver.createModel()
        logger.debug("Add variables")
        # ToDo: add variables
        frequencies = {}
        for line in line_pool.getLines():
            frequency = model.addVariable(0, float('inf'), VariableType.INTEGER, name=f"f_{line.getId()}")
            frequencies[line] = frequency

        acceptableLineIds = compute_acceptable_line_ids(line_pool, compute_shortest_paths(ptn, od, parameters), ptn)

        d = {}
        for origin in ptn.getNodes():
            d[origin.getId()] = {}
            for destination in ptn.getNodes():
                d[origin.getId()][destination.getId()] = {}
                sumOfAllVariablesPerODPair = None
                if origin == destination or od.getValue(origin.getId(), destination.getId()) == 0:
                    continue
                for lineId in acceptableLineIds[(origin.getId(), destination.getId())]:
                    d[origin.getId()][destination.getId()][lineId] = model.addVariable(0, od.getValue(origin.getId(),
                                                                                                      destination.getId()),
                                                                                       VariableType.INTEGER,
                                                                                       name=f"d{origin.getId()}{destination.getId()}{lineId}")
                    if sumOfAllVariablesPerODPair is None:
                        sumOfAllVariablesPerODPair = d[origin.getId()][destination.getId()][lineId]
                    else:
                        sumOfAllVariablesPerODPair += d[origin.getId()][destination.getId()][lineId]

                if not sumOfAllVariablesPerODPair:
                    sumOfAllVariablesPerODPair = 0

                model.addConstraint(sumOfAllVariablesPerODPair, ConstraintSense.LESS_EQUAL,
                                    od.getValue(origin.getId(), destination.getId()),
                                    name=f"od_constraint{origin.getId()}_{destination.getId()}")

        logger.debug("Adding more constraints")
        # ToDo: add constraints
        for link in ptn.getEdges():
            sum_freq_per_line = model.createExpression()
            for line in line_pool.getLines():
                if link in line.getLinePath().getEdges():
                    sum_freq_per_line.add(frequencies[line])
            model.addConstraint(sum_freq_per_line, ConstraintSense.LESS_EQUAL, link.getUpperFrequencyBound(),
                                f"u_{link.getId()}")
            model.addConstraint(sum_freq_per_line, ConstraintSense.GREATER_EQUAL, link.getLowerFrequencyBound(),
                                f"l_{link.getId()}")

        logger.debug("Add capacity constraints")
        # Constraint 3.7 -> Ensure that the capacity of each line is not exceeded
        capacity = parameters.get_capacity()
        for link in ptn.getEdges():
            direct_travellers_on_line_and_edge = {}
            for line in line_pool.getLines():
                if link not in line.getLinePath().getEdges():
                    continue
                for origin in ptn.getNodes():
                    for destination in ptn.getNodes():
                        if origin == destination or od.getValue(origin.getId(), destination.getId()) == 0:
                            continue
                        od_pair = (origin.getId(), destination.getId())
                        if line.getId() not in acceptableLineIds.get(od_pair):
                            continue
                        if link not in acceptableLineIds.get(od_pair).get(line.getId()).getEdges():
                            continue

                        if line.getId() not in direct_travellers_on_line_and_edge:
                            direct_travellers_on_line_and_edge[line.getId()] = model.createExpression()
                        direct_travellers_on_line_and_edge[line.getId()].multiAdd(1,
                                                                                  d.get(origin.getId()).get(
                                                                                      destination.getId()).get(
                                                                                      line.getId()))
                capacity_of_line = model.createExpression()
                capacity_of_line.multiAdd(capacity, frequencies.get(line))
                # There may be a line that is not acceptable for anybody
                direct_travellers_on_line = direct_travellers_on_line_and_edge.get(line.getId())
                if direct_travellers_on_line is not None:
                    model.addConstraint(direct_travellers_on_line, ConstraintSense.LESS_EQUAL, capacity_of_line,
                                        "capacity_constraint_" + str(link.getId()) + "_" + str(line.getId()))

        logger.debug("Add parameters")
        parameters.setSolverParameters(model)
        # model.setSense(OptimizationSense.MINIMIZE)

        #objectives = list()
        model.getObjective().clear()
        obj = None
        for line, frequency in frequencies.items():
            if obj is None:
                obj = line.getCost() * frequency
            else:
                obj += line.getCost() * frequency

        #objectives.append(obj)

        obj2 = None
        for origin, destinations in d.items():
            for destination, lines in destinations.items():
                for line, variable in lines.items():
                    if obj2 is None:
                        obj2 = variable
                    else:
                        obj2 += variable

        #objectives.append(obj2)
        if obj2:
            combined_obj = obj - obj2
        else:
            combined_obj = obj

I tried to output all parameters of feasable solutions, but couldnt find any differences in the output data. All direct tavlers and costs are identical aswell as the final combined_obj value. I think it has to do with the constraints I am giving, since they dont allow a specific assignment for the direct travlers?

-> Maybe there is a workaround for Gurobi to only output same results with equal given parameters only once?

Upvotes: 0

Views: 80

Answers (0)

Related Questions