def left_ortho_complement(matrix): # commented out for performance #assert has_left_ortho_complement(matrix), "There is no leftorthocomplement!" v = custom_simplify( st.nullspaceMatrix(matrix.T).T ) assert is_zero_matrix(v*matrix), "Leftorthocomplement is not correct." return v
def left_ortho_complement(matrix): # commented out for performance #assert has_left_ortho_complement(matrix), "There is no leftorthocomplement!" v = custom_simplify(st.nullspaceMatrix(matrix.T).T) assert is_zero_matrix(v * matrix), "Leftorthocomplement is not correct." return v
def right_ortho_complement(matrix): assert has_right_ortho_complement(matrix), "There is no rightorthocomplement!" if roc=="conv": v = custom_simplify( st.nullspaceMatrix(matrix) ) assert is_zero_matrix(matrix*v), "Leftorthocomplement is not correct." return v else: return alternative_right_ortho_complement(matrix)
def right_ortho_complement(matrix): assert has_right_ortho_complement( matrix), "There is no rightorthocomplement!" if roc == "conv": v = custom_simplify(st.nullspaceMatrix(matrix)) assert is_zero_matrix(matrix * v), "Leftorthocomplement is not correct." return v else: return alternative_right_ortho_complement(matrix)
def unimod_inv(M, s=None, t=None, time_dep_symbs=[], simplify_nsm=True, max_deg=None): """ Assumes that M(s) is an unimodular polynomial matrix and calculates its inverse which is again unimodular :param M: Matrix to be inverted :param s: Derivative Symbol :param time_dep_symbs: sequence of time dependent symbols :param max_deg: maximum polynomial degree w.r.t. s of the ansatz :return: Minv """ assert isinstance(M, sp.MatrixBase) assert M.is_square n = M.shape[0] degree_m = nc_degree(M, s) if max_deg is None: # upper bound according to # Levine 2011, On necessary and sufficient conditions for differential flatness, p. 73 max_deg = (n - 1) * degree_m assert int(max_deg) == max_deg assert max_deg >= 0 C = M * 0 free_params = [] for i in range(max_deg + 1): prefix = 'c{0}_'.format(i) c_part = st.symbMatrix(n, n, prefix, commutative=False) C += nc_mul(c_part, s**i) free_params.extend(list(c_part)) P = nc_mul(C, M) - sp.eye(n) P2 = right_shift_all(P, s, t, time_dep_symbs).reshape(n * n, 1) deg_P = nc_degree(P2, s) part_eqns = [] for i in range(deg_P + 1): # omit the highest order (because it behaves like in the commutative case) res = P2.diff(s, i).subs(s, 0) #/sp.factorial(i) part_eqns.append(res) eqns = st.row_stack(*part_eqns) # equations for all degrees of s # now non-commutativity is inferring eqns2, st_c_nc = make_all_symbols_commutative(eqns) free_params_c, st_c_nc_free_params = make_all_symbols_commutative( free_params) # find out which of the equations are (in)homogeneous eqns2_0 = eqns2.subs(st.zip0(free_params_c)) assert eqns2_0.atoms() in ({0, -1}, {-1}, set()) inhom_idcs = st.np.where(st.to_np(eqns2_0) != 0)[0] hom_idcs = st.np.where(st.to_np(eqns2_0) == 0)[0] eqns_hom = sp.Matrix(st.np.array(eqns2)[hom_idcs]) eqns_inh = sp.Matrix(st.np.array(eqns2)[inhom_idcs]) assert len(eqns_inh) == n # find a solution for the homogeneous equations # if this is not possible, M was not unimodular Jh = eqns_hom.jacobian(free_params_c).expand() nsm = st.nullspaceMatrix(Jh, simplify=simplify_nsm, sort_rows=True) na = nsm.shape[1] if na < n: msg = 'Could not determine sufficiently large nullspace. '\ 'Either M is not unimodular or the expressions are to complicated.' # TODO: decide which of the two cases occurs, via substitution of # random numbers and singular value decomposition # (or application of st.generic_rank) raise ValueError(msg) # parameterize the inhomogenous equations with the solution of the homogeneous equations # new free parameters: aa = st.symb_vector('_a1:{0}'.format(na + 1)) nsm_a = nsm * aa eqns_inh2 = eqns_inh.subs(lzip(free_params_c, nsm_a)) # now solve the remaining equations # solve the linear system Jinh = eqns_inh2.jacobian(aa) rhs_inh = -eqns_inh2.subs(st.zip0(aa)) assert rhs_inh == sp.ones(n, 1) sol_vect = Jinh.solve(rhs_inh) sol = lzip(aa, sol_vect) # get the values for all free_params (now they are not free anymore) free_params_sol_c = nsm_a.subs(sol) # replace the commutative symbols with the original non_commutative symbols (of M) free_params_sol = free_params_sol_c.subs(st_c_nc) Minv = C.subs(lzip(free_params, free_params_sol)) return Minv
#~ [ 0, 0, 0, 0, 1, -1, 1, -1, 0, 0, 0, 0], #~ [W2*x9, W3*x10, W1*x11 - W2*x11, W1*x12 - W3*x12, Rd*W1 + Rl*W2 - Rl*W3, Rl*W2 + Rl*W3, Rd*W1, 0, W2*x1, W3*x2, W1*x3 - W2*x3, W1*x4 - W3*x4]]) P00 = F_eq.jacobian(xx) #~ P00 = sp.Matrix([ #~ [ x9, 0, -x11, 0, Rl, Rl, 0, 0, x1, 0, -x3, 0], #~ [ 0, x10, 0, -x12, -Rl, Rl, 0, 0, 0, x2, 0, -x4], #~ [ 0, 0, 0, 0, -x9, 0, 0, 0, -x5, 0, 0, 0], #~ [ 0, 0, 0, 0, 0, -x10, 0, 0, 0, -x6, 0, 0], #~ [ 0, 0, 0, 0, 0, 0, -x11, 0, 0, 0, -x7, 0], #~ [ 0, 0, 0, 0, 0, 0, 0, -x12, 0, 0, 0, -x8], #~ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #~ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #~ [W2*xdot9, W3*xdot10, W1*xdot11 - W2*xdot11, W1*xdot12 - W3*xdot12, 0, 0, 0, 0, W2*xdot1, W3*xdot2, W1*xdot3 - W2*xdot3, W1*xdot4 - W3*xdot4]]) P10_roc = st.nullspaceMatrix(P10) #~ P10_roc = sp.Matrix([ #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [ 0, 0, 0], #~ [-W3*x2, x3*(-W1 + W2), x4*(-W1 + W3)], #~ [ W2*x1, 0, 0], #~ [ 0, W2*x1, 0], #~ [ 0, 0, W2*x1]]) # statt P10_rpinv nehme ich jetzt S mit einheitsvektoren sodass
def unimod_inv(M, s=None, t=None, time_dep_symbs=[], simplify_nsm=True, max_deg=None): """ Assumes that M(s) is an unimodular polynomial matrix and calculates its inverse which is again unimodular :param M: Matrix to be inverted :param s: Derivative Symbol :param time_dep_symbs: sequence of time dependent symbols :param max_deg: maximum polynomial degree w.r.t. s of the ansatz :return: Minv """ assert isinstance(M, sp.MatrixBase) assert M.is_square n = M.shape[0] degree_m = nc_degree(M, s) if max_deg is None: # upper bound according to # Levine 2011, On necessary and sufficient conditions for differential flatness, p. 73 max_deg = (n - 1)*degree_m assert int(max_deg) == max_deg assert max_deg >= 0 C = M*0 free_params = [] for i in range(max_deg+1): prefix = 'c{0}_'.format(i) c_part = st.symbMatrix(n, n, prefix, commutative=False) C += nc_mul(c_part, s**i) free_params.extend(list(c_part)) P = nc_mul(C, M) - sp.eye(n) P2 = right_shift_all(P, s, t, time_dep_symbs).reshape(n*n, 1) deg_P = nc_degree(P2, s) part_eqns = [] for i in range(deg_P + 1): # omit the highest order (because it behaves like in the commutative case) res = P2.diff(s, i).subs(s, 0)#/sp.factorial(i) part_eqns.append(res) eqns = st.row_stack(*part_eqns) # equations for all degrees of s # now non-commutativity is inferring eqns2, st_c_nc = make_all_symbols_commutative(eqns) free_params_c, st_c_nc_free_params = make_all_symbols_commutative(free_params) # find out which of the equations are (in)homogeneous eqns2_0 = eqns2.subs(st.zip0(free_params_c)) assert eqns2_0.atoms() in ({0, -1}, {-1}, set()) inhom_idcs = st.np.where(st.to_np(eqns2_0) != 0)[0] hom_idcs = st.np.where(st.to_np(eqns2_0) == 0)[0] eqns_hom = sp.Matrix(st.np.array(eqns2)[hom_idcs]) eqns_inh = sp.Matrix(st.np.array(eqns2)[inhom_idcs]) assert len(eqns_inh) == n # find a solution for the homogeneous equations # if this is not possible, M was not unimodular Jh = eqns_hom.jacobian(free_params_c).expand() nsm = st.nullspaceMatrix(Jh, simplify=simplify_nsm, sort_rows=True) na = nsm.shape[1] if na < n: msg = 'Could not determine sufficiently large nullspace. '\ 'Either M is not unimodular or the expressions are to complicated.' # TODO: decide which of the two cases occurs, via substitution of # random numbers and singular value decomposition # (or application of st.generic_rank) raise ValueError(msg) # parameterize the inhomogenous equations with the solution of the homogeneous equations # new free parameters: aa = st.symb_vector('_a1:{0}'.format(na+1)) nsm_a = nsm*aa eqns_inh2 = eqns_inh.subs(lzip(free_params_c, nsm_a)) # now solve the remaining equations # solve the linear system Jinh = eqns_inh2.jacobian(aa) rhs_inh = -eqns_inh2.subs(st.zip0(aa)) assert rhs_inh == sp.ones(n, 1) sol_vect = Jinh.solve(rhs_inh) sol = lzip(aa, sol_vect) # get the values for all free_params (now they are not free anymore) free_params_sol_c = nsm_a.subs(sol) # replace the commutative symbols with the original non_commutative symbols (of M) free_params_sol = free_params_sol_c.subs(st_c_nc) Minv = C.subs(lzip(free_params, free_params_sol)) return Minv