Exemple #1
0
    def test_block_selector_ends_fixed(self):
        der_fixed = [[True, True],
                     [True, True],
                     [True, True],
                     [True, True],
                     [True, True]]

        expect = sp.sparse.identity(10, dtype=int, format="coo")

        np.testing.assert_array_equal(
            selector.block_selector(der_fixed).todense(), expect.todense())
Exemple #2
0
    def test_block_selector_ends_fixed_middle_0th_fixed(self):
        der_fixed = [[True, True, True],
                     [True, False, True],
                     [True, False, True],
                     [True, False, True],
                     [True, False, True]]

        expect = sp.sparse.coo_matrix((np.ones(20, dtype=int),
                                       ([0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10,
                                         11, 12, 13, 14, 11, 12, 13, 14],
                                        [0, 1, 2, 3, 4, 5, 10, 15, 16, 17, 18,
                                         19, 6, 7, 8, 9, 11, 12, 13, 14])),
                                      shape=(15, 20))

        np.testing.assert_array_equal(
            selector.block_selector(der_fixed).todense(), expect.todense())
Exemple #3
0
    def get_free_ders(self,
                      waypoints_changed=None,
                      der_fixed_changed=None,
                      times_changed=None):
        """Solve for free derivatives of polynomial segments

        Richter, Bry, Roy; Polynomial Trajectory Planning for Quadrotor Flight
        Equation 31

        Uses:
            self.
            waypoints: Numpy array of the waypoints (including derivatives)
            times: time in which to complete each segment (not the transition
                times)
            cost: weight in the sum of Hessian matrices (Equation 15)
            order: the order of the polynomial segments
            der_fixed: Boolean array of n_der (max potential number of free
                derivatives per segment) x n_seg + 1 (one column per waypoint).
                Fixing a derivative at a waypoint is performed by setting the
                corresponding entry to True.

        # TODO([email protected]) - decide how many of these fields to store vs
        # recompute
        Modifies:
            self.
            free_ders: Numpy matrix (column vector) of the free derivatives
            fixed_ders: Numpy matrix (column vector) of the fixed derivatives
            Q: the cost matrix in terms of polynomial coefficients
            M: the selector matrix mapping the ordering of derivatives to/from
                the form where free and fixed derivatives are partitioned
            A: the constraint matrix for segment boundaries
            pinv_A: the (pseudo-)inverse of A
            R: the cost matrix in terms of the free derivatives

        Args:

        Returns:

        Raises:
            minsnap.exceptions.InputError if
                np.size(times) != np.shape(der_fixed)[1] - 1
        """

        # def get_free_ders_setup_matrices(self, waypoints_changed=None,
        #                   der_fixed_changed=None,
        #                   times_changed=None):
        start_timer = time.time()

        if times_changed is None:
            times_changed = np.r_[0:self.n_seg]
        if der_fixed_changed is None:
            der_fixed_changed = np.r_[0:self.n_seg + 1]
        if waypoints_changed is None:
            waypoints_changed = np.r_[0:self.n_seg + 1]

        waypoints = self.waypoints
        times = self.times
        costs = self.costs
        order = self.order
        der_fixed = self.der_fixed
        der_ineq = self.der_ineq
        delta = self.delta
        n_seg = self.n_seg
        n_der = utils.n_coeffs_free_ders(order)[1]
        n_ineq = sum(sum(der_ineq))

        if np.size(times) != np.shape(der_fixed)[1] - 1:
            raise exceptions.InputError(
                times, "Mismatch between number of segment times" +
                " and number of segments")

        if np.shape(waypoints) != np.shape(der_fixed):
            raise exceptions.InputError(
                waypoints, "Mismatch between size of waypoints" +
                " array and size of derivative fixed" + "array")

        waypoints = np.matrix(waypoints)

        if n_ineq > 0:
            #TODO([email protected] & [email protected]) - investigate other ways to prevent singular matrices here
            limit = 0.03
            if sum(np.array(times) < limit) > 0:
                print(
                    "Warning: changing times because a lower limit has been reached"
                )
                temp = np.array(times)
                temp[temp < limit] = limit
                times = np.array(temp)
                self.times = times

        # See README.md on MATLAB vs Octave vs Numpy linear equation system solving
        # Porting this code: R{i} = M{i} / A{i}' * Q{i} / A{i} * M{i}';
        # With even polynomial order, the odd number of coefficients is not equal
        # to twice the number of free derivatives (floor of (odd # / 2)).
        # Therefore, A is not square.

        # Based on some quick checks, the inverse of A is still quite sparse,
        # especially when only the 0th derivative is fixed at internal
        # waypoints.

        # convert COO sparse output to CSC for fast matrix arithmetic
        if np.size(times_changed) or self.Q is None or self.A is None:
            if (self.Q is None
                    or self.A is None):  #or np.size(times_changed) > 1):
                Q = cost.block_cost(times, costs, order).tocsc(copy=True)
                A = constraint.block_constraint(times, order).tocsc(copy=True)
            else:
                # if we know which segment times have changed, only update
                # the corresponding blocks in the block matrix
                cost.update(self.Q, times_changed, times[times_changed], costs,
                            order)
                constraint.update(self.A, times_changed, times[times_changed],
                                  order)
                Q = self.Q
                A = self.A

            if (A.shape[0] == A.shape[1]):
                pinv_A = sp.sparse.linalg.inv(A)
                # TODO([email protected]) - could this be made to outperform the line above?
                #pinv_A = constraint.invert(A, order)
            else:
                # is there some way to keep this sparse? sparse SVD?
                pinv_A = np.asmatrix(sp.linalg.pinv(A.todense()))
        else:
            # TODO([email protected]) - is this the cleanest way?
            Q = self.Q
            A = self.A
            pinv_A = self.pinv_A

        if np.size(der_fixed_changed) or self.M is None:
            M = selector.block_selector(
                der_fixed, closed_loop=self.closed_loop).tocsc(copy=True)
        else:
            # TODO([email protected]) - is this the cleanest way?
            M = self.M

        if np.size(times_changed) or np.size(
                der_fixed_changed) or self.R is None:
            # all are matrices; OK to use * for multiply
            # R{i} = M{i} * pinv(full(A{i}))' * Q{i} * pinv(full(A{i})) * M{i}';
            R = M * pinv_A.T * Q * pinv_A * M.T

            # partition R by slicing along columns, converting to csr, then slicing
            # along rows
            if self.closed_loop:
                num_der_fixed = np.sum(der_fixed[:, :-1])
            else:
                num_der_fixed = np.sum(der_fixed)

            # Equation 29
            try:
                R_free = R[:, num_der_fixed:].tocsr()
            except AttributeError:
                # oops - we are a numpy matrix
                R_free = R[:, num_der_fixed:]
            R_fixed_free = R_free[:num_der_fixed, :]
            R_free_free = R_free[num_der_fixed:, :]

        else:
            R = self.R

            if hasattr(self, 'R_fixed_free'):
                R_fixed_free = self.R_fixed_free
                R_free_free = self.R_free_free
            else:
                # partition R by slicing along columns, converting to csr, then slicing
                # along rows
                if self.closed_loop:
                    num_der_fixed = np.sum(der_fixed[:, :-1])
                else:
                    num_der_fixed = np.sum(der_fixed)

                # Equation 29
                try:
                    R_free = R[:, num_der_fixed:].tocsr()
                except AttributeError:
                    # oops - we are a numpy matrix
                    R_free = R[:, num_der_fixed:]
                R_fixed_free = R_free[:num_der_fixed, :]
                R_free_free = R_free[num_der_fixed:, :]

        # TODO([email protected]) - transpose waypoints and der_fixed at input
        if not self.closed_loop:
            fixed_ders = waypoints.T[np.nonzero(der_fixed.T)].T  # Equation 31
        else:
            fixed_ders = waypoints[:, :-1].T[np.nonzero(
                der_fixed[:, :-1].T)].T  # Equation 31
        """ Solve """
        # the fixed derivatives, D_F in the paper, are just the waypoints for which
        # der_fixed is true
        # DP{i} = -RPP \ RFP' * DF{i};

        if n_ineq == 0:
            # Run for unconstrained case:
            # Solve for the free derivatives
            # Solve the unconstrained system
            free_ders = np.asmatrix(
                sp.sparse.linalg.spsolve(R_free_free,
                                         -R_fixed_free.T * fixed_ders)).T

        # Run for Constrained cases
        elif n_ineq > 0:  # If there are inequality constraints
            # Inequalities
            # Isolate the waypoints for which there is an inequality
            ineq_way_p = waypoints.T[np.nonzero(der_ineq.T)].T

            if type(delta) != float:
                # Take out the delta for the inequality constrained parts
                ineq_delta = delta.T[np.nonzero(der_ineq.T)].reshape(
                    [ineq_way_p.shape[0], 1])
            else:
                # Just a constant
                ineq_delta = delta

            W = np.concatenate((
                (ineq_way_p - ineq_delta),
                (-ineq_way_p - ineq_delta),
            ),
                               axis=0)

            # Selector matix
            if np.size(der_fixed_changed) or not hasattr(self, 'E'):
                E = constraint.block_ineq_constraint(der_fixed,
                                                     der_ineq).tocsc(copy=True)
            elif self.E is None:
                E = constraint.block_ineq_constraint(der_fixed,
                                                     der_ineq).tocsc(copy=True)
            else:
                E = self.E

            ### Solve with CVXOPT
            # Setup matrices
            P = matrix(2 * R_free_free.toarray(), tc='d')
            q_vec = matrix(np.array(2 * fixed_ders.T * R_fixed_free).T, tc='d')
            G = matrix(-E.toarray().astype(np.double), tc='d')
            h_vec = matrix(np.array(-W), tc='d')

            # Checks on the problem setup
            if np.linalg.matrix_rank(np.concatenate((P, G))) < P.size[0]:
                print('Warning: rank of [P;G] {} is less than size of P: {}'.
                      format(np.linalg.matrix_rank(np.concatenate((P, G))),
                             P.size[0]))
            else:
                if self.print_output:
                    print(
                        'Rank of A is {} size is {}\nRank for Q is {}, size is {}'
                        .format(np.linalg.matrix_rank(A.toarray()), A.shape,
                                np.linalg.matrix_rank(Q.toarray()), Q.shape))
                    print('Rank of R is {}, size is {}'.format(
                        np.linalg.matrix_rank(R.toarray()), R.shape))
                    print(
                        'Rank P is {}\nRank of G is: {}\nRank of [P;G] {} size of P: {}\n'
                        .format(np.linalg.matrix_rank(P),
                                np.linalg.matrix_rank(G),
                                np.linalg.matrix_rank(np.concatenate((P, G))),
                                P.size[0]))

            # To suppress output
            solvers.options['show_progress'] = False

            # Run cvxopt solver
            sol = solvers.qp(P, q_vec, G, h_vec)  #,initvals=primalstart)

            # Solution
            free_ders = np.matrix(sol['x'])

            if self.print_output:
                print('cvx solution is:\n{}'.format(free_ders))
                print('cvx cost is:\n{}'.format(sol['primal objective']))
                print('Constraints are: \n{}'.format(E * free_ders - W))

        # self.fixed_terms = fixed_terms
        self.opt_time = time.time() - start_timer
        self.free_ders = free_ders
        self.fixed_ders = fixed_ders
        self.Q = Q
        self.M = M
        self.A = A
        self.pinv_A = pinv_A
        self.R = R
        self.R_fixed_free = R_fixed_free
        self.R_free_free = R_free_free
Exemple #4
0
 def test_block_selector_reference(self):
     der_fixed = utils.nested_copy(self.reference_der_fixed)
     expect = selector.block_selector(der_fixed)
     np.testing.assert_array_equal(selector.block_selector(
         self.reference_der_fixed).todense(), expect.todense())