Пример #1
0
    def solveModel(self):
        """
        Call the specified solver to solve the problem.

        Returns
        -------
            self.data.objs[0] : Current objective value
            step_norm         : Current step size inf norm
            feasibility       : Current feasibility measure

        This also caches the previous values of the vars, just in case
        we need to access them later if a step is rejected
        """
        current_decision_values = self.getCurrentDecisionVariableValues()
        self.data.previous_model_state = self.getCurrentModelState()
        results = self.solver.solve(self.model,
                                    keepfiles=self.config.keepfiles,
                                    tee=self.config.tee)

        if not check_optimal_termination(results):
            raise ArithmeticError(
                'EXIT: Model solve failed with status {} and termination'
                ' condition(s) {}.'.format(
                    str(results.solver.status),
                    str(results.solver.termination_condition)))

        self.model.solutions.load_from(results)
        new_decision_values = self.getCurrentDecisionVariableValues()
        step_norm = self.calculateStepSizeInfNorm(current_decision_values,
                                                  new_decision_values)
        feasibility = self.calculateFeasibility()
        return self.data.objs[0](), step_norm, feasibility
Пример #2
0
    def test_3x3_using_linear_regression(self):
        """ simple linear regression with two x columns, so 3x3 Hessian"""

        model = self._simple_model()
        solver = pe.SolverFactory("ipopt")
        status = solver.solve(model)
        self.assertTrue(check_optimal_termination(status))
        tstar = [
            pe.value(model.b0),
            pe.value(model.b['tofu']),
            pe.value(model.b['chard'])
        ]

        def _ndwrap(x):
            # wrapper for numdiff call
            model.b0.fix(x[0])
            model.b["tofu"].fix(x[1])
            model.b["chard"].fix(x[2])
            rval = pe.value(model.SSE)
            return rval

        H = nd.Hessian(_ndwrap)(tstar)
        HInv = np.linalg.inv(H)

        model.b0.fixed = False
        model.b["tofu"].fixed = False
        model.b["chard"].fixed = False
        status, H_inv_red_hess = inv_reduced_hessian_barrier(
            model, [model.b0, model.b["tofu"], model.b["chard"]])
        # this passes at decimal=6, BTW
        np.testing.assert_array_almost_equal(HInv, H_inv_red_hess, decimal=3)
Пример #3
0
def test_solve_cvrp_optimal(network):
    """
    Checks if solved model returns optimal solution flag.
    """

    model = CVRPModel(network)
    result = solve_model(model)

    assert check_optimal_termination(result), \
        "solve_cvrp should return optimal results for example network"
Пример #4
0
 def test_conopt_optimal(self):
     with ReaderFactory("sol") as reader:
         if reader is None:
             raise IOError("Reader 'sol' is not registered")
         soln = reader(join(currdir, "conopt_optimal.sol"))
         self.assertEqual(soln.solver.termination_condition,
                          TerminationCondition.optimal)
         self.assertEqual(soln.solution.status, SolutionStatus.optimal)
         self.assertEqual(soln.solver.status, SolverStatus.ok)
         self.assertTrue(check_optimal_termination(soln))
         assert_optimal_termination(soln)
Пример #5
0
    def test_infeasible1(self):
        with ReaderFactory("sol") as reader:
            if reader is None:
                raise IOError("Reader 'sol' is not registered")
            soln = reader(join(currdir, "infeasible1.sol"))
            self.assertEqual(soln.solver.termination_condition,
                             TerminationCondition.infeasible)
            self.assertEqual(soln.solution.status, SolutionStatus.infeasible)
            self.assertEqual(soln.solver.status, SolverStatus.warning)

            self.assertFalse(check_optimal_termination(soln))

            with self.assertRaises(RuntimeError):
                assert_optimal_termination(soln)
Пример #6
0
def inv_reduced_hessian_barrier(model,
                                independent_variables,
                                bound_tolerance=1e-6,
                                tee=False):
    """
    This function computes the inverse of the reduced Hessian of a problem at the
    solution. This function first solves the problem with Ipopt and then generates
    the KKT system for the barrier subproblem to compute the inverse reduced hessian.

    For more information on the reduced Hessian, see "Numerical Optimization", 2nd Edition
    Nocedal and Wright, 2006.
    
    The approach used in this method can be found in, "Computational Strategies for 
    the Optimal Operation of Large-Scale Chemical Processes", Dissertation, V. Zavala
    2008. See section 3.2.1.

    Parameters
    ----------
    model : Pyomo model
        The Pyomo model that we want to solve and analyze
    independent_variables : list of Pyomo variables
        This is the list of independent variables for computing the reduced hessian.
        These variables must not be at their bounds at the solution of the 
        optimization problem.
    bound_tolerance : float
       The tolerance to use when checking if the variables are too close to their bound.
       If they are too close, then the routine will exit without a reduced hessian.
    tee : bool
       This flag is sent to the tee option of the solver. If true, then the solver
       log is output to the console.
    """
    m = model

    # make sure the necessary suffixes are added
    # so the reduced hessian kkt system is setup correctly from
    # the ipopt solution
    if not hasattr(m, 'ipopt_zL_out'):
        m.ipopt_zL_out = pyo.Suffix(direction=pyo.Suffix.IMPORT)
    if not hasattr(m, 'ipopt_zU_out'):
        m.ipopt_zU_out = pyo.Suffix(direction=pyo.Suffix.IMPORT)
    if not hasattr(m, 'ipopt_zL_in'):
        m.ipopt_zL_in = pyo.Suffix(direction=pyo.Suffix.EXPORT)
    if not hasattr(m, 'ipopt_zU_in'):
        m.ipopt_zU_in = pyo.Suffix(direction=pyo.Suffix.EXPORT)
    if not hasattr(m, 'dual'):
        m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT)

    # create the ipopt solver
    solver = pyo.SolverFactory('ipopt')
    # set options to prevent bounds relaxation (and 0 slacks)
    solver.options['bound_relax_factor'] = 0
    solver.options['honor_original_bounds'] = 'no'
    # solve the problem
    status = solver.solve(m, tee=tee)
    if not check_optimal_termination(status):
        return status, None

    # compute the barrier parameter
    # ToDo: this needs to eventually come from the solver itself
    estimated_mu = list()
    for v in m.ipopt_zL_out:
        if v.has_lb():
            estimated_mu.append((pyo.value(v) - v.lb) * m.ipopt_zL_out[v])
    for v in m.ipopt_zU_out:
        if v.has_ub():
            estimated_mu.append((v.ub - pyo.value(v)) * m.ipopt_zU_out[v])
    if len(estimated_mu) == 0:
        mu = 10**-8.6
    else:
        mu = sum(estimated_mu) / len(estimated_mu)
        # check to make sure these estimates were all reasonable
        if any([abs(mu - estmu) > 1e-7 for estmu in estimated_mu]):
            print(
                'Warning: estimated values of mu do not seem consistent - using mu=10^(-8.6)'
            )
            mu = 10**-8.6

    # collect the list of var data objects for the independent variables
    ind_vardatas = list()
    for v in independent_variables:
        if v.is_indexed():
            for k in v:
                ind_vardatas.append(v[k])
        else:
            ind_vardatas.append(v)

    # check that none of the independent variables are at their bounds
    for v in ind_vardatas:
        if (v.has_lb() and pyo.value(v) - v.lb <= bound_tolerance) or \
           (v.has_ub() and v.ub - pyo.value(b) <= bound_tolerance):
            raise ValueError(
                "Independent variable: {} has a solution value that is near"
                " its bound (according to tolerance). The reduced hessian"
                " computation does not support this at this time. All"
                " independent variables should be in their interior.".format(
                    v))

    # find the list of indices that we need to make up the reduced hessian
    kkt_builder = InteriorPointInterface(m)
    pyomo_nlp = kkt_builder.pyomo_nlp()
    ind_var_indices = pyomo_nlp.get_primal_indices(ind_vardatas)

    # setup the computation of the reduced hessian
    kkt_builder.set_barrier_parameter(mu)
    kkt = kkt_builder.evaluate_primal_dual_kkt_matrix()
    linear_solver = ScipyInterface(compute_inertia=False)
    linear_solver.do_symbolic_factorization(kkt)
    linear_solver.do_numeric_factorization(kkt)

    n_rh = len(ind_var_indices)
    rhs = np.zeros(kkt.shape[0])
    inv_red_hess = np.zeros((n_rh, n_rh))

    for rhi, vari in enumerate(ind_var_indices):
        rhs[vari] = 1
        v = linear_solver.do_back_solve(rhs)
        rhs[vari] = 0
        for rhj, varj in enumerate(ind_var_indices):
            inv_red_hess[rhi, rhj] = v[varj]

    return status, inv_red_hess
Пример #7
0
 def find_solution(self) -> Tuple[List[List[Tuple[int, int]]], float]:
     """
     Run an LP solver for MAPF
     :return: Path for each agent
     """
     # Guard against trivial case
     starts = self.starts
     goals = self.goals
     num_agents = len(starts)
     agents = list(range(num_agents))
     solve_time = 0.0
     if starts == goals:
         return [[starts[agent]] for agent in agents], solve_time
     # Start search for a solution at the lowest possible sum-of-cost (xi = xi_0)
     agents_path = []
     for xi in itertools.count(self.xi_0):
         print('Searching xi = %d' % xi)
         mu = self.mu(xi)  # Required number of time expansions
         T = self.time_expand(mu)  # Time expanded graph
         model = pyo.ConcreteModel()
         model.nodes = pyo.Set(dimen=3, initialize=T.nodes)
         model.edges = pyo.Set(within=model.nodes * model.nodes, initialize=T.edges)
         model.agents = pyo.Set(initialize=agents)
         model.x = pyo.Var(model.agents, model.edges,
                           domain=pyo.NonNegativeIntegers,
                           initialize=0)
         model.obj = pyo.Objective(expr=pyo.summation(
             model.x,
             index={(agent, e)
                    for agent in agents
                    for e in T.in_edges((*goals[agent], mu))}),
             sense=pyo.maximize)
         model.capacity = pyo.ConstraintList()
         for e in T.edges:
             model.capacity.add(
                 pyo.summation(
                     model.x,
                     index={(agent, e) for agent in agents}) <= 1)
         model.conservation = pyo.ConstraintList()
         model.sources = pyo.ConstraintList()
         model.sinks = pyo.ConstraintList()
         model.vertex_collisions = pyo.ConstraintList()
         for v in T.nodes:
             if T.succ[v]:
                 model.vertex_collisions.add(
                     pyo.summation(
                         model.x,
                         index={(agent, e) for e in T.out_edges(v) for agent in agents}) <= 1)
             for agent in agents:
                 if v == (*starts[agent], 0):
                     model.sources.add(
                         pyo.summation(
                             model.x,
                             index={(agent, e) for e in T.out_edges(v)}) == 1)
                     continue
                 if v == (*goals[agent], mu):
                     model.sinks.add(
                         pyo.summation(
                             model.x,
                             index={(agent, e) for e in T.in_edges(v)}) == 1)
                     continue
                 model.conservation.add(
                     pyo.summation(
                         model.x,
                         index={(agent, e) for e in T.in_edges(v)}) -
                     pyo.summation(
                         model.x,
                         index={(agent, e) for e in T.out_edges(v)}) == 0)
         model.edge_collisions = pyo.ConstraintList()
         for u, v in T.edges:
             if u > v and ((*v[:2], u[2]), (*u[:2], v[2])) in T.edges:
                 model.edge_collisions.add(
                     pyo.summation(
                         model.x,
                         index={(agent, x, u[2], y, v[2])
                                for agent, (x, y) in itertools.product(
                                 agents,
                                 itertools.permutations([u[:2], v[:2]]))}
                     ) <= 1
                 )
         model.extra_edges = pyo.Constraint(expr=pyo.summation(
             model.x,
             index={(agent, u, v)
                    for agent, (u, v) in itertools.product(agents, T.edges)
                    if u[2] in range(self.individual_costs[agent], mu)
                    and not u[:2] == v[:2] == goals[agent]}
         ) == self.delta(xi))
         sum_of_costs = float('inf')
         while sum_of_costs != xi:
             results = self.opt.solve(model, timelimit=60)
             solve_time += results.solver.time
             if check_optimal_termination(results):
                 agent_attr = {e: agent
                               for e in T.edges
                               for agent in agents
                               if pyo.value(model.x[agent, e])}
                 nx.set_edge_attributes(T, values=agent_attr, name='agent')
                 moves = sorted((data['agent'], u[-1], u[:-1], v[:-1])
                                for u, v, data in T.edges(data=True)
                                if 'agent' in data.keys())
                 agents_moves = [[move[2:] for move in moves]
                                 for k, moves in itertools.groupby(moves, key=lambda x: x[0])]
                 agents_path = [[agent_move[0] for agent_move in agent_moves] + [agent_moves[-1][-1]]
                                for agent_moves in agents_moves]
                 agents_path = [
                     list(
                         reversed(
                             [agent_path[-1]] + list(itertools.dropwhile(lambda x: x == agent_path[-1],
                                                                         reversed(agent_path)))
                         )
                     )
                     for agent_path in agents_path
                 ]
                 sum_of_costs = sum(len(agent_path) - 1 for agent_path in agents_path)
                 if sum_of_costs != xi:
                     # Rare: more than one solution with exactly delta extra edges; an agent waited at its goal
                     # then later departed it, meaning there is a non-extra edge which should be an extra edge.
                     # Specifically, the non-extra edge "wait" action at the goal is actually an extra edge.
                     # The following technique was attempted here:
                     # Pivot to another solution by cutting out the current solution's combination of edges.
                     # Since each solution is uniquely defined by its combination of edges, we add a constraint
                     # making the current combination of edges infeasible, forcing a new solution.
                     # However, it did not work.
                     # We output a message informing of the existence of the solution
                     # but regrettably return a suboptimal one.
                     print('***RARE: GLPK returned another solution, see comments!!!***')
                     print('Solve time: %f' % solve_time)
                     print('Sum of costs (GLPK\'s solution): %d' % sum_of_costs)
                     print('Sum of costs (Actual): %d' % xi)
                     print('Makespan (mu): %d' % mu)
                     print('Extra edges (delta): %d' % self.delta(xi))
                     print('Lower bound on sum of costs (xi_0): %d' % self.xi_0)
                     print('Due to technical limitations, GLPK\'s solution will be shown')
                     sum_of_costs = xi
                 else:
                     print('***Found solution***')
                     print('Solve time: %f' % solve_time)
                     print('Sum of costs (xi): %d' % xi)
                     print('Makespan (mu): %d' % mu)
                     print('Extra edges (delta): %d' % self.delta(xi))
                     print('Lower bound on sum of costs (xi_0): %d' % self.xi_0)
             else:
                 break
         if sum_of_costs == xi:
             break
     return agents_path, solve_time