def _ip_helper(self, with_bounds, with_ineq, linear_solver):
        t0 = 0
        delta_t = 1
        num_finite_elements = 90
        constant_control_duration = 10
        time_scale = 0.1
        num_time_blocks = 3
        interface = Problem(t0=t0,
                            delta_t=delta_t,
                            num_finite_elements=num_finite_elements,
                            constant_control_duration=constant_control_duration,
                            time_scale=time_scale,
                            num_time_blocks=num_time_blocks,
                            with_bounds=with_bounds,
                            with_ineq=with_ineq)
        options = parapint.algorithms.IPOptions()
        options.linalg.solver = linear_solver
        status = parapint.algorithms.ip_solve(interface=interface, options=options)
        self.assertEqual(status, parapint.algorithms.InteriorPointStatus.optimal)
        interface.load_primals_into_pyomo_model()
        x = dict()
        p = dict()
        local_block_indices = _distribute_blocks(num_time_blocks, rank, size)
        for ndx in local_block_indices:
            m = interface.pyomo_model(ndx)
            for t in m.x_time_points:
                if t in x:
                    self.assertAlmostEqual(x[t], m.x[t].value)
                else:
                    x[t] = m.x[t].value
            for t in m.p_time_points:
                p[t] = m.p[t].value

        m = build_time_block(t0=t0,
                             delta_t=delta_t,
                             num_finite_elements=num_finite_elements,
                             constant_control_duration=constant_control_duration,
                             time_scale=time_scale,
                             with_bounds=with_bounds,
                             with_ineq=with_ineq)
        opt = pe.SolverFactory('ipopt')
        res = opt.solve(m, tee=True)
        assert_optimal_termination(res)
        for _t, _x in x.items():
            self.assertAlmostEqual(_x, m.x[_t].value)
        for _t, _p in p.items():
            self.assertAlmostEqual(_p, m.p[_t].value)
    def test_kkt_system(self):
        t0 = 0
        delta_t = 1
        num_finite_elements = 90
        constant_control_duration = 10
        time_scale = 0.1
        num_time_blocks = 3
        interface = Problem(t0=t0,
                            delta_t=delta_t,
                            num_finite_elements=num_finite_elements,
                            constant_control_duration=constant_control_duration,
                            time_scale=time_scale,
                            num_time_blocks=num_time_blocks)
        interface.set_primals(interface.init_primals())
        interface.set_slacks(interface.init_slacks())
        interface.set_duals_eq(interface.init_duals_eq())
        interface.set_duals_ineq(interface.init_duals_ineq())
        interface.set_duals_primals_lb(interface.init_duals_primals_lb())
        interface.set_duals_primals_ub(interface.init_duals_primals_ub())
        interface.set_duals_slacks_lb(interface.init_duals_slacks_lb())
        interface.set_duals_slacks_ub(interface.init_duals_slacks_ub())
        interface.set_barrier_parameter(0)
        kkt = interface.evaluate_primal_dual_kkt_matrix()
        rhs = interface.evaluate_primal_dual_kkt_rhs()
        linear_solver = parapint.linalg.ScipyInterface()
        local_kkt = coo_matrix(kkt.to_local_array())
        linear_solver.do_symbolic_factorization(local_kkt)
        linear_solver.do_numeric_factorization(local_kkt)
        sol = linear_solver.do_back_solve(rhs.make_local_copy())
        interface.set_primal_dual_kkt_solution(sol)
        interface.set_primals(interface.get_primals() + interface.get_delta_primals())
        interface.set_slacks(interface.get_slacks() + interface.get_delta_slacks())
        interface.set_duals_eq(interface.get_duals_eq() + interface.get_delta_duals_eq())
        interface.set_duals_ineq(interface.get_duals_ineq() + interface.get_delta_duals_ineq())
        interface.set_duals_primals_lb(interface.get_duals_primals_lb() + interface.get_delta_duals_primals_lb())
        interface.set_duals_primals_ub(interface.get_duals_primals_ub() + interface.get_delta_duals_primals_ub())
        interface.set_duals_slacks_lb(interface.get_duals_slacks_lb() + interface.get_delta_duals_slacks_lb())
        interface.set_duals_slacks_ub(interface.get_duals_slacks_ub() + interface.get_delta_duals_slacks_ub())
        interface.load_primals_into_pyomo_model()
        x = dict()
        p = dict()
        local_block_indices = _distribute_blocks(num_time_blocks, rank, size)
        for ndx in local_block_indices:
            m = interface.pyomo_model(ndx)
            for t in m.x_time_points:
                if t in x:
                    self.assertAlmostEqual(x[t], m.x[t].value)
                else:
                    x[t] = m.x[t].value
            for t in m.p_time_points:
                p[t] = m.p[t].value

        m = build_time_block(t0=t0,
                             delta_t=delta_t,
                             num_finite_elements=num_finite_elements,
                             constant_control_duration=constant_control_duration,
                             time_scale=time_scale)
        opt = pe.SolverFactory('ipopt')
        res = opt.solve(m)
        assert_optimal_termination(res)
        for _t, _x in x.items():
            self.assertAlmostEqual(_x, m.x[_t].value)
        for _t, _p in p.items():
            self.assertAlmostEqual(_p, m.p[_t].value)
    def setUpClass(cls) -> None:
        cls.t0 = 0
        cls.delta_t = 1
        cls.num_finite_elements = 6
        cls.constant_control_duration = 2
        cls.time_scale = 1
        cls.num_time_blocks = 3
        cls.with_bounds = True
        cls.with_ineq = False
        cls.barrier_parameter = 0.1
        cls.interface = Problem(t0=cls.t0,
                                delta_t=cls.delta_t,
                                num_finite_elements=cls.num_finite_elements,
                                constant_control_duration=cls.constant_control_duration,
                                time_scale=cls.time_scale,
                                num_time_blocks=cls.num_time_blocks,
                                with_bounds=cls.with_bounds,
                                with_ineq=cls.with_ineq)
        interface = cls.interface
        num_time_blocks = cls.num_time_blocks

        primals = BlockVector(num_time_blocks + 1)
        duals_eq = BlockVector(num_time_blocks)
        duals_ineq = BlockVector(num_time_blocks)
        duals_primals_lb = BlockVector(num_time_blocks + 1)
        duals_primals_ub = BlockVector(num_time_blocks + 1)
        duals_slacks_lb = BlockVector(num_time_blocks)
        duals_slacks_ub = BlockVector(num_time_blocks)

        ownership_map = _get_ownership_map(num_time_blocks, size)

        val_map = pe.ComponentMap()

        if ownership_map[0] == rank:
            m = interface.pyomo_model(0)
            val_map[m.x[0]] = 0
            val_map[m.x[1]] = 1
            val_map[m.x[2]] = 2
            val_map[m.p[0]] = 0.5
            val_map[m.cons[1]] = 1
            val_map[m.cons[2]] = 2

        if ownership_map[1] == rank:
            m = interface.pyomo_model(1)
            val_map[m.x[2]] = 2
            val_map[m.x[3]] = 3
            val_map[m.x[4]] = 4
            val_map[m.p[2]] = 1
            val_map[m.cons[3]] = 3
            val_map[m.cons[4]] = 4

        if ownership_map[2] == rank:
            m = interface.pyomo_model(2)
            val_map[m.x[4]] = 4
            val_map[m.x[5]] = 5
            val_map[m.x[6]] = 6
            val_map[m.p[4]] = 1.5
            val_map[m.cons[5]] = 5
            val_map[m.cons[6]] = 6

        for ndx in range(num_time_blocks):
            primals.set_block(ndx, np.zeros(4, dtype=np.double))
            duals_primals_lb.set_block(ndx, np.zeros(4, dtype=np.double))
            duals_primals_ub.set_block(ndx, np.zeros(4, dtype=np.double))
            duals_ineq.set_block(ndx, np.zeros(0, dtype=np.double))
            duals_slacks_lb.set_block(ndx, np.zeros(0, dtype=np.double))
            duals_slacks_ub.set_block(ndx, np.zeros(0, dtype=np.double))
            sub_duals_eq = BlockVector(3)
            sub_duals_eq.set_block(0, np.zeros(2, dtype=np.double))
            if ndx == 0:
                sub_duals_eq.set_block(1, np.zeros(0, dtype=np.double))
            else:
                sub_duals_eq.set_block(1, np.zeros(1, dtype=np.double))
            if ndx == num_time_blocks - 1:
                sub_duals_eq.set_block(2, np.zeros(0, dtype=np.double))
            else:
                sub_duals_eq.set_block(2, np.zeros(1, dtype=np.double))
            duals_eq.set_block(ndx, sub_duals_eq)
        primals.set_block(num_time_blocks, np.zeros(2, dtype=np.double))
        duals_primals_lb.set_block(num_time_blocks, np.zeros(2, dtype=np.double))
        duals_primals_ub.set_block(num_time_blocks, np.zeros(2, dtype=np.double))

        local_block_indices = _distribute_blocks(num_time_blocks, rank, size)
        for ndx in local_block_indices:
            primals.set_block(ndx, np.array([val_map[i] for i in interface.get_pyomo_variables(ndx)], dtype=np.double))
            duals_primals_ub.set_block(ndx, np.array([0, 0, 0, ndx], dtype=np.double))
            sub_duals_eq = duals_eq.get_block(ndx)
            sub_duals_eq.set_block(0, np.array([val_map[i] for i in interface.get_pyomo_constraints(ndx)], dtype=np.double))
            if ndx == 0:
                sub_duals_eq.set_block(1, np.zeros(0, dtype=np.double))
            else:
                sub_duals_eq.set_block(1, np.ones(1, dtype=np.double) * ndx)
            if ndx == num_time_blocks - 1:
                sub_duals_eq.set_block(2, np.zeros(0, dtype=np.double))
            else:
                sub_duals_eq.set_block(2, np.ones(1, dtype=np.double) * ndx)

        primals_flat = primals.flatten()
        res = np.zeros(primals_flat.size, dtype=np.double)
        comm.Allreduce(primals_flat, res)
        primals.copyfrom(res)

        duals_primals_lb_flat = duals_primals_lb.flatten()
        res = np.zeros(duals_primals_lb_flat.size, dtype=np.double)
        comm.Allreduce(duals_primals_lb_flat, res)
        duals_primals_lb.copyfrom(res)

        duals_primals_ub_flat = duals_primals_ub.flatten()
        res = np.zeros(duals_primals_ub_flat.size, dtype=np.double)
        comm.Allreduce(duals_primals_ub_flat, res)
        duals_primals_ub.copyfrom(res)

        duals_eq_flat = duals_eq.flatten()
        res = np.zeros(duals_eq_flat.size, dtype=np.double)
        comm.Allreduce(duals_eq_flat, res)
        duals_eq.copyfrom(res)

        primals.set_block(num_time_blocks, np.array([3, 6], dtype=np.double))
        duals_primals_lb.set_block(num_time_blocks, np.zeros(2, dtype=np.double))
        duals_primals_ub.set_block(num_time_blocks, np.zeros(2, dtype=np.double))
        interface.set_primals(primals)
        interface.set_duals_eq(duals_eq)
        interface.set_duals_ineq(duals_ineq)
        interface.set_duals_slacks_lb(duals_slacks_lb)
        interface.set_duals_slacks_ub(duals_slacks_ub)
        interface.set_duals_primals_lb(duals_primals_lb)
        interface.set_duals_primals_ub(duals_primals_ub)
        interface.set_barrier_parameter(cls.barrier_parameter)