def _compute_propagation_step(self, shapes, constant_input, step_constant): """Compute a calculation specification for the update step. """ ode_symbol_factor_h = self.propagator_matrices[0][shapes[0].order, shapes[0].order] constant_term = "(" + str(ode_symbol_factor_h) + ") * " + str(self.ode_symbol) + \ "+ (" + str(constant_input) + ") * (" + str(step_constant) + ")" self.propagator = {} self.ode_updates = [str(self.ode_symbol) + " = " + constant_term] for p, shape in zip(self.propagator_matrices, shapes): P = zeros(shape.order + 1, shape.order + 1) for i in range(shape.order + 1): for j in range(shape.order + 1): if simplify(p[i, j]) != sympify(0): symbol_p_i_j = "__P_{}__{}_{}".format(shape.symbol, i, j) P[i, j] = parse_expr(symbol_p_i_j) self.propagator[symbol_p_i_j] = str(p[i, j]) y = zeros(shape.order + 1, 1) for i in range(shape.order): y[i] = shape.state_variables[i] y[shape.order] = self.ode_symbol P[shape.order, shape.order] = 0 z = P * y self.ode_updates.append(str(self.ode_symbol) + " += " + str(z[shape.order])) shape.state_updates = P[:shape.order, :shape.order] * y[:shape.order, 0]
def computeGlobalStiffnessMatrix(K, element_data, nodal_data, updateProgressBarFunc): number_of_elements = len(element_data) stiffness_calculated = False local_k = zeros(8, 8) # loop over all elements for i in range(number_of_elements): element_node_number_vector = element_data[i].getNodalVector() if stiffness_calculated == False: ele_node_coord = zeros(4, 2) C = element_data[i].calculateConstitutiveMatrix( ) #this has no density effect in for j in range(len(element_node_number_vector)): node_index = element_node_number_vector[j] - 1 node = nodal_data[node_index] node_position_vector = node.getPositionVector2D() ele_node_coord[j, 0] = node_position_vector[0] ele_node_coord[j, 1] = node_position_vector[1] local_k = calcLocalQ4StiffnessMatrix(ele_node_coord, C) stiffness_calculated = True # Now apply density effects rho_power_p = element_data[i].getRhoPowerP() this_local_k = deepcopy(local_k) this_local_k *= rho_power_p element_data[i].setElementK(this_local_k) # add to global matrix addLocalMatrixToGlobalMatrix(this_local_k, K, element_node_number_vector) updateProgressBarFunc(int(i / number_of_elements * 100 - 20))
def prde_no_cancel_b_large(b, Q, n, DE): """ Parametric Poly Risch Differential Equation - No cancellation: deg(b) large enough. Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with b != 0 and either D == d/dt or deg(b) > max(0, deg(D) - 1), returns h1, ..., hr in k[r] and a matrix A with coefficients in Const(k) such that if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and Dq + b*Q == Sum(ci*qi, (i, 1, m)), then q = Sum(dj*hj, (j, 1, r)), where d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. """ db = b.degree(DE.t) m = len(Q) H = [Poly(0, DE.t)] * m for N in xrange(n, -1, -1): # [n, ..., 0] for i in range(m): si = Q[i].nth(N + db) / b.LC() sitn = Poly(si * DE.t**N, DE.t) H[i] = H[i] + sitn Q[i] = Q[i] - derivation(sitn, DE) - b * sitn if all(qi.is_zero for qi in Q): dc = -1 M = zeros(0, 2) else: dc = max([qi.degree(t) for qi in Q]) M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i)) A, u = constant_system(M, zeros(dc + 1, 1), DE) c = eye(m) A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c)) return (H, A)
def prde_no_cancel_b_large(b, Q, n, DE): """ Parametric Poly Risch Differential Equation - No cancellation: deg(b) large enough. Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with b != 0 and either D == d/dt or deg(b) > max(0, deg(D) - 1), returns h1, ..., hr in k[r] and a matrix A with coefficients in Const(k) such that if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and Dq + b*Q == Sum(ci*qi, (i, 1, m)), then q = Sum(dj*hj, (j, 1, r)), where d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. """ db = b.degree(DE.t) m = len(Q) H = [Poly(0, DE.t)]*m for N in xrange(n, -1, -1): # [n, ..., 0] for i in range(m): si = Q[i].nth(N + db)/b.LC() sitn = Poly(si*DE.t**N, DE.t) H[i] = H[i] + sitn Q[i] = Q[i] - derivation(sitn, DE) - b*sitn if all(qi.is_zero for qi in Q): dc = -1 M = zeros(0, 2) else: dc = max([qi.degree(t) for qi in Q]) M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i)) A, u = constant_system(M, zeros(dc + 1, 1), DE) c = eye(m) A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c)) return (H, A)
def __init__(self, levels): """ """ # total number of states self.levels = levels # defining the symbolic Hamiltonian matrix self.hamiltonian = zeros(levels, levels) # defining the couplings and rabi rate matrices # couplings contains the frequencies between levels # rabi contains the rabi rates of the couplings between levels self.couplings = zeros(levels, levels) self.rabi = zeros(levels, levels) # level detunings list self.detunings = [] # numer of state couplings from an initial level self.cpl = np.zeros([levels, 1]) # frequencies list self.frequencies = [] # energies list self.energies = self.hamiltonian.diagonal() # by default no zero energy defined self.zero_energy = None self.transformed = None
def test(B0,Ts,E,A,B,C,U,V,Rc,Rs,Ss,p,m,rt): D1=BlockDiagMatrix(B0,eye(p)).as_mutable() D2=BlockMatrix([[Ts,U],[-V,zeros(p,m)]]).as_mutable() D3=BlockMatrix([[s*E-A,B],[-C,zeros(C.rows,B.cols)]]).as_mutable() D4Block11=simplify((Ss*Rs.inv())).as_mutable() D4=BlockDiagMatrix(D4Block11,eye(m)).as_mutable() return simplify(D1*D2)==simplify(D3*D4)
def calcLocalQ4StiffnessMatrix(ele_node_coord, C): GP = Matrix([[-0.577350269189626, 0.577350269189626], [0.577350269189626, 0.577350269189626], [-0.577350269189626, -0.577350269189626], [0.577350269189626, -0.577350269189626]]) WtFac = np.array([1, 1, 1, 1]) ##ShapeFunctions xi = sp.symbols('xi') eta = sp.symbols('eta') N1 = ((1 - xi) * (1 - eta)) / 4 # shapefunction node 1 N2 = ((1 + xi) * (1 - eta)) / 4 # shapefunction node 2 N3 = ((1 + xi) * (1 + eta)) / 4 # shapefunction node 3 N4 = ((1 - xi) * (1 + eta)) / 4 # shapefunction node 4 Ni = Matrix([[N1, N2, N3, N4]]) # assemble shapefunctions dNi_dxi = sp.diff(Ni, xi) # derive shapefunctions for xi dNi_deta = sp.diff(Ni, eta) # derive shapefunctions for eta ##calculate Jacobian J + inverse J_element = Matrix([dNi_dxi, dNi_deta]) * ele_node_coord J_elememt_inverse = sp.Inverse(J_element) J_element_eval = sp.lambdify((xi, eta), J_element) ##calculate B matrix B = zeros(3, 8) # initialize B for j in range(4): index_counter = j * 2 dNj_dxi_deta = Matrix([[dNi_dxi[j]], [dNi_deta[j]]]) dNj_dxdy = J_elememt_inverse * dNj_dxi_deta # calculate dNj_dx,_dy temp_B = Matrix([[dNj_dxdy[0], 0], [0, dNj_dxdy[1]], [dNj_dxdy[1], dNj_dxdy[0]]]) B[0:3, index_counter:(index_counter + 2)] = temp_B # assemble B B_eval = sp.lambdify((xi, eta), B) det = la.det # move outside of loop K_stiff_i = zeros(8, 8) # initialize local element stiffness matrix ####### 2) --> loop over all Gauss Points n_GP = 4 for j in range(n_GP): gp_weight = WtFac[j] # current gauss point weight gp_xi = GP[j, 0] # current gauss point coordinate xi gp_eta = GP[j, 1] # current gauss point coordinate eta B_j = B_eval(gp_xi, gp_eta) B_j_transpose = B_j.T # transpose B J_element_j = J_element_eval(gp_xi, gp_eta) det_J_element_j = det(J_element_j) # calculate current det(J) # evaluate element stiffness matrix at current GP (2D - integration) K_stiff_i += B_j_transpose * C * B_j * det_J_element_j * gp_weight * gp_weight return K_stiff_i
def test(rE, r, p, m, PE, PA, PC, As, Bs, Cs, Ds, E, A, B, C, D): D1Block2 = simplify(PC * s * (PE - s * PA).inv()) D1Block3 = BlockMatrix([[Bs], [Ds]]).as_mutable() D1Block4 = BlockMatrix([[zeros(r, p)], [eye(p)]]).as_mutable() D1 = BlockMatrix([[eye(r + p), D1Block2, D1Block3, D1Block4]]).as_mutable() D2 = BlockMatrix(2, 2, [s * E - A, B, -C, D]).as_mutable() D3 = BlockMatrix(2, 2, [As, Bs, -Cs, Ds]).as_mutable() D4 = BlockMatrix( [[eye(r), zeros(r, rE + 2 * p), zeros(r, m)], [zeros(m, r), zeros(m, rE + 2 * p), eye(m)]] ).as_mutable() return simplify(D1 * D2) == simplify(D3 * D4)
def test(B0,Ts,E,E0,A0,A,B,C,U,V,Rc,Rs,Qs,Ss,p,m,rt,n): D1=BlockMatrix([[zeros(n,rt+p)],[eye(rt +p)]]).as_mutable() D2=BlockMatrix([[Ts,U],[-V,zeros(p,m)]]).as_mutable() D3=BlockMatrix([[s*E-A,B],[-C,zeros(C.rows,B.cols)]]).as_mutable() D4Block1=simplify((-Ss*(Qs.inv()))).as_mutable() D4Block1=D4Block1.col_join(eye(rt)) D4=BlockDiagMatrix(D4Block1,eye(m)).as_mutable() return simplify(D1*D2) == simplify(D3*D4)
def __init__(self, levels): """ Parameters: levels : number of levels in the optical Bloch equations system """ self.density_matrix = zeros(levels, levels) self.dissipator = zeros(levels, levels) self.branching = zeros(levels, levels) self.decay_rate = zeros(levels, 1) self.levels = levels self.generateDensityMatrix()
def generate_strong_Z(alpha, d): """ Z satisfies there are at least one "1" in each column """ Z = zeros(alpha, d) while Z.rank() != alpha: Z = zeros(alpha, d) for i in range(d): N = random.randint(1, alpha) # N means randomly choose how many "1" in this column randNs = random.sample(range(alpha), N) for j in range(N): t = randNs[j] Z[t, i] = 1 return Z
def generate_stronger_Z(alpha, d): """ full-rank Z has at least k "1" in each row """ k=d-alpha+1 Z = zeros(alpha, d) while Z.rank() != alpha: Z = zeros(alpha, d) for i in range(alpha): N = random.randint(k,d) randNs = random.sample(range(d), N) for j in range(N): t = randNs[j] Z[i,t] = 1 return Z
def solve_lin_sys(eqs, ring): """Solve a system of linear equations. """ assert ring.domain.has_Field # transform from equations to matrix form xs = ring.gens M = zeros(len(eqs), len(xs) + 1, cls=RawMatrix) for j, e_j in enumerate(eqs): for i, x_i in enumerate(xs): M[j, i] = e_j.coeff(x_i) M[j, -1] = -e_j.coeff(1) eqs = M # solve by row-reduction echelon, pivots = eqs.rref(iszerofunc=lambda x: not x, simplify=lambda x: x) # construct the returnable form of the solutions if pivots[-1] == len(xs): return None elif len(pivots) == len(xs): sol = [ring.ground_new(s) for s in echelon[:, -1]] return dict(zip(xs, sol)) else: sols = {} for i, p in enumerate(pivots): vect = RawMatrix([[-x] for x in xs[p + 1:]] + [[ring.one]]) sols[xs[p]] = (echelon[i, p + 1:] * vect)[0] return sols
def addDecay(self, initial_state, final_state, gamma): """ Add a decay to the dissipator matrix between two states, set by initial_state and final_state. Parameters: initial_state : initial coupled state final_state : final coupled state gamma : decay rate from initial_state to final_state """ if (initial_state >= self.levels) or (final_state >= self.levels): raise AssertionError('Specified state exceeds number of levels.') if initial_state == final_state: raise AssertionError('State cannot decay into itself.') # adding the decay to the dissipator G = zeros(self.levels, self.levels) G[final_state, initial_state] = sqrt(gamma) self.dissipator -= Rational(1/2) * \ anti_commute(G.T@G, self.density_matrix) - [email protected][email protected] self.dissipator = simplify(self.dissipator) # update decay rates decay_rate_old = self.decay_rate[initial_state] decay_rate_new = decay_rate_old + gamma self.decay_rate[initial_state] += gamma # add the decay to the branching ratio matrix for i in range(self.levels): if i == final_state: self.branching[initial_state, i] = \ (self.branching[initial_state, i]*decay_rate_old+gamma)/decay_rate_new else: self.branching[initial_state, i] = \ (self.branching[initial_state, i]*decay_rate_old)/decay_rate_new
def exp_deriv_generators(self, params): ''' constructs the generators for computing the first derivative of the time ordered exponential of self, with respect to params Note: I'll need to either add in stuff that keeps track of where the blocks go, or just have a convention that is maintained everywhere. Convention is easier, but it might be nice to also return some data structure with this info ''' D, C = self.parameter_decomposition(params) new_mats = [] for sys_idx in range(len(self.mat_list)): G = self.mat_list[sys_idx] m0 = zeros(self.shape[sys_idx]) for d_idx in range(len(params)): A = C[d_idx].mat_list[sys_idx] new_mats.append(Matrix(BlockMatrix([[G, A], [m0, G]]))) return Sym_UTB_Matrix(new_mats)
def matrix_simplify(M): n, m = M.shape Md = zeros((n, m)) for i in range(n): for j in range(m): Md[i,j] = simplify(M[i,j]) return Md
def fp_eval(s,re,rx,se,sx,b): re = re rx = rx se = se sx = sx b = b theta = Matrix([-1, 0, re,re]) sd = s[0] st = s[1] m = 'm' V = 'V' mu0 = zeros(4,4) Sigma0 = Matrix([[se**2,0,0, 0],[0,sx**2,0, 0],[0,0,sd**2,0],[0,0,0,st**2]]) I = eye(4) Ii = Matrix([[0,0,0,0],[0,1,0,0],[0,0,0,0],[0,0,0,1]]) Ic = I - Ii psi1 = Matrix([1,1,rx-re,rx-re]) Psi1 = bayes_coef(psi1,Sigma0) beliefs0 = {m : mu0, V : Sigma0} beliefs1 = bayes_update(Psi1,beliefs0) phi = (b*re/(1 - b*re)*theta.transpose()*(I - beliefs1[m])).transpose() + Matrix([0,1,0,0]) phic = Ic*phi phii = Ii*phi psi2 = phii + Matrix([0,0,rx,rx]) psi2alt = phic - 1/(1-b*re)*theta Psi2 = bayes_coef(psi2, beliefs1[V]) beliefs2 = bayes_update(Psi2, beliefs1) beliefs2alt= bayes_update(bayes_coef(psi2alt,beliefs1[V]),beliefs1) delta = (theta.transpose()*(I - beliefs2[m])).transpose() deltac = Ic*delta deltai = Ii*delta sdvalue = (deltac.transpose()*beliefs0[V]*deltac)[0]**0.5 stvalue = (deltai.transpose()*beliefs0[V]*deltai)[0]**0.5
def sym(self, refls, v): para = self.para_weyl(refls) s = zeros(self.rank, 1) for w_mat in para.values(): s += self.expand_in_roots(w_mat * self.C * v) return s / len(para)
def test_diagonal_symmetrical(): m = PropertiesOnlyMatrix(2, 2, [0, 1, 1, 0]) assert not m.is_diagonal() assert m.is_symmetric() assert m.is_symmetric(simplify=False) m = PropertiesOnlyMatrix(2, 2, [1, 0, 0, 1]) assert m.is_diagonal() m = PropertiesOnlyMatrix(3, 3, diag(1, 2, 3)) assert m.is_diagonal() assert m.is_symmetric() m = PropertiesOnlyMatrix(3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3]) assert m == diag(1, 2, 3) m = PropertiesOnlyMatrix(2, 3, zeros(2, 3)) assert not m.is_symmetric() assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0), (0, 6), (0, 0))) assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0, 0), (0, 6, 0))) assert m.is_diagonal() m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) assert m.is_symmetric() assert not m.is_symmetric(simplify=False) assert m.expand().is_symmetric(simplify=False)
def create_M(self): """ Функция вызывается только в конструкторе Создает матрицу, определяющую систему уравнений относительно лямбда и вычисляет ее ранг """ self.M = zeros(2 * self.dimension, self.dimension) for row in range(2 * self.dimension): for col in range(self.dimension): if (system.th(col, self.lambda_count + self.v_count) in self.families[row]): """ !!!Поскольку в рамках задачи значения g i-ых не влияют на ранг матрицы, принимаем их все равными 1 """ if (not self.need_g): self.M[row, col] = 1 else: if (row % 2 == 0): sd = 0 for i in range(self.lambda_count + self.v_count): if (self.th(row, self.lambda_count + self.v_count)[i] != self.th(col, self.lambda_count + self.v_count)[i]): sd = i self.M[row, col] = self.g[sd] else: sd = 0 for i in range(self.lambda_count + self.v_count): if (self.th(int(row / 2), self.lambda_count + self.v_count)[i] != self.th(col, self.lambda_count + self.v_count)[i]): sd = i self.M[row, col] = self.g[self.lambda_count + self.v_count + sd] self.M_rank = self.M.rank()
def enlarge_two_opt_sympy(self, opt, qubit0, qubit1, num): """Enlarge two-qubit operator to n qubits. It is exponential in the number of qubits. Args: opt (Matrix): the matrix that represents a two-qubit gate. It looks like this:: Matrix([ [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]]) qubit0 (int): id of the control qubit qubit1 (int): id of the target qubit num (int): the number of qubits in the system. Returns: Matrix: the enlarged matrix that operates on all qubits in the system. It is basically a tensorproduct of the gates applied on each qubit (Identity gate if no gate is applied to the qubit). """ enlarge_opt = zeros(2**num, 2**num) # np.zeros([1 << (num), 1 << (num)]) for i in range(2**(num-2)): for j in range(2): for k in range(2): for m in range(2): for n in range(2): enlarge_index1 = index2(j, qubit0, k, qubit1, i) enlarge_index2 = index2(m, qubit0, n, qubit1, i) enlarge_opt[enlarge_index1, enlarge_index2] = opt[j+2*k, m+2*n] return enlarge_opt
def components2vec(components): vec = zeros(3, 1) for i in range(0, 3): ind = (i, ) if (ind in components.keys()): vec[i] = components[ind] return (vec)
def from_concise_description(cls, shape, nc_sym, nc_idx, c_sym, c_idx): ''' constructs the object from the description format output by the function concise_description() ''' # need to construct a list of matrices from the concise description # instantiate a list of zero Matrix objects mat_list = [] for d in shape: mat_list.append(zeros(d, d)) # populate the non-commutative symbols for k in range(len(nc_sym)): sym = nc_sym[k] for mat_idx, i, j in nc_idx[k]: mat_list[mat_idx][i, j] = sym # populate hte list of commutative symbols for k in range(len(c_sym)): sym = c_sym[k] for mat_idx, i, j in c_idx[k]: mat_list[mat_idx][i, j] = sym return Sym_UTB_Matrix(mat_list)
def _extractUpperTriangle(self, A, nrow=None, ncol=None): ''' Extract the upper triangle of matrix A Parameters ---------- A: :mod:`sympy.matrices.matrices` input matrix nrow: int number of row ncol: int number of column Returns ------- :mod:`sympy.matrices.matrices` An upper triangle matrix ''' if nrow is None: nrow = len(A[:,0]) if ncol is None: ncol = len(A[0,:]) B = zeros(nrow, ncol) for i in range(0, nrow): for j in range(i, ncol): B[i,j] = A[i,j] return B
def sigma(k): s = zeros(3) e = eye(3) for i in range(3): for j in range(3): s[i, j] = (im if i == k else e)[i,j] return s
def _extractUpperTriangle(self, A, nrow=None, ncol=None): ''' Extract the upper triangle of matrix A Parameters ---------- A: :mod:`sympy.matrices.matrices` input matrix nrow: int number of row ncol: int number of column Returns ------- :mod:`sympy.matrices.matrices` An upper triangle matrix ''' if nrow is None: nrow = len(A[:, 0]) if ncol is None: ncol = len(A[0, :]) B = zeros(nrow, ncol) for i in range(0, nrow): for j in range(i, ncol): B[i, j] = A[i, j] return B
def RGS_generalized(m): """ Computes the m + 1 generalized unrestricted growth strings and returns them as rows in matrix. Examples ======== >>> from sympy.combinatorics.partitions import RGS_generalized >>> RGS_generalized(6) Matrix([ [ 1, 1, 1, 1, 1, 1, 1], [ 1, 2, 3, 4, 5, 6, 0], [ 2, 5, 10, 17, 26, 0, 0], [ 5, 15, 37, 77, 0, 0, 0], [ 15, 52, 151, 0, 0, 0, 0], [ 52, 203, 0, 0, 0, 0, 0], [203, 0, 0, 0, 0, 0, 0]]) """ d = zeros(m + 1) for i in range(0, m + 1): d[0, i] = 1 for i in range(1, m + 1): for j in range(m): if j <= m - i: d[i, j] = j * d[i - 1, j] + d[i - 1, j + 1] else: d[i, j] = 0 return d
def get_precedence_matrix(self): """ Gets the precedence matrix. This is used for computing the distance between two permutations. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation.josephus(3,6,1) >>> p Permutation([2, 5, 3, 1, 4, 0]) >>> p.get_precedence_matrix() [0, 0, 0, 0, 0, 0] [1, 0, 0, 0, 1, 0] [1, 1, 0, 1, 1, 1] [1, 1, 0, 0, 1, 0] [1, 0, 0, 0, 0, 0] [1, 1, 0, 1, 1, 0] See Also ======== get_precedence_distance, get_adjacency_matrix, get_adjacency_distance """ m = zeros(self.size) perm = self.array_form for i in xrange(m.rows): for j in xrange(i + 1, m.cols): m[perm[i], perm[j]] = 1 return m
def get_adjacency_matrix(self): """ Computes the adjacency matrix of a permutation. If job i is adjacent to job j in a permutation p then we set m[i, j] = 1 where m is the adjacency matrix of p. Examples: >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation.josephus(3,6,1) >>> p.get_adjacency_matrix() [0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 1, 0] [0, 0, 0, 0, 0, 1] [0, 1, 0, 0, 0, 0] [1, 0, 0, 0, 0, 0] [0, 0, 0, 1, 0, 0] >>> from sympy.combinatorics.permutations import Permutation >>> q = Permutation([0, 1, 2, 3]) >>> q.get_adjacency_matrix() [0, 1, 0, 0] [0, 0, 1, 0] [0, 0, 0, 1] [0, 0, 0, 0] """ m = zeros(self.size) perm = self.array_form for i in xrange(self.size - 1): m[perm[i], perm[i + 1]] = 1 return m
def param_rischDE(fa, fd, G, DE): """ Solve a Parametric Risch Differential Equation: Dy + f*y == Sum(ci*Gi, (i, 1, m)). """ _, (fa, fd) = weak_normalizer(fa, fd, DE) a, (ba, bd), G, hn = prde_normal_denom(ga, gd, G, DE) A, B, G, hs = prde_special_denom(a, ba, bd, G, DE) g = gcd(A, B) A, B, G = A.quo(g), B.quo(g), [ gia.cancel(gid * g, include=True) for gia, gid in G ] Q, M = prde_linear_constraints(A, B, G, DE) M, _ = constant_system(M, zeros(M.rows, 1), DE) # Reduce number of constants at this point try: # Similar to rischDE(), we try oo, even though it might lead to # non-termination when there is no solution. At least for prde_spde, # it will always terminate no matter what n is. n = bound_degree(A, B, G, DE, parametric=True) except NotImplementedError: # Useful for debugging: # import warnings # warnings.warn("param_rischDE: Proceeding with n = oo; may cause " # "non-termination.") n = oo A, B, Q, R, n1 = prde_spde(A, B, Q, n, DE)
def test_diagonal_symmetrical(): m = PropertiesOnlyMatrix(2, 2, [0, 1, 1, 0]) assert not m.is_diagonal() assert m.is_symmetric() assert m.is_symmetric(simplify=False) m = PropertiesOnlyMatrix(2, 2, [1, 0, 0, 1]) assert m.is_diagonal() m = PropertiesOnlyMatrix(3, 3, diag(1, 2, 3)) assert m.is_diagonal() assert m.is_symmetric() m = PropertiesOnlyMatrix(3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3]) assert m == diag(1, 2, 3) m = PropertiesOnlyMatrix(2, 3, zeros(2, 3)) assert not m.is_symmetric() assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0), (0, 6), (0, 0))) assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0, 0), (0, 6, 0))) assert m.is_diagonal() m = Matrix(3, 3, [1, x**2 + 2 * x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) assert m.is_symmetric() assert not m.is_symmetric(simplify=False) assert m.expand().is_symmetric(simplify=False)
def gradient(f, varls): """ Calcula el gradiente de una función f(x1,x2,...)""" n = len(varls) G = zeros(n, 1) for i in range(n): G[i] = f.diff(varls[i]) return G
def nullspace(matrix, simplify=False): """Returns list of vectors (Matrix objects) that span nullspace of self """ from sympy.matrices import zeros simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify reduced, pivots = matrix.rref(simplify=simpfunc) basis = [] # create a set of vectors for the basis for i in range(matrix.cols - len(pivots)): basis.append(zeros(matrix.cols, 1)) # contains the variable index to which the vector corresponds basiskey, cur = [-1] * len(basis), 0 for i in range(matrix.cols): if i not in pivots: basiskey[cur] = i cur += 1 for i in range(matrix.cols): if i not in pivots: # free var, just set vector's ith place to 1 basis[basiskey.index(i)][i, 0] = 1 else: # add negative of nonpivot entry to corr vector for j in range(i + 1, matrix.cols): line = pivots.index(i) v = reduced[line, j] if simplify: v = simpfunc(v) if v: if j in pivots: # XXX: Is this the correct error? raise NotImplementedError( "Could not compute the nullspace of matrix self.") basis[basiskey.index(j)][i, 0] = -v return [matrix._new(b) for b in basis]
def limited_integrate(fa, fd, G, DE): """ Solves the limited integration problem: f = Dv + Sum(ci*wi, (i, 1, n)) """ fa, fd = fa * Poly(1 / fd.LC(), DE.t), fd.monic() A, B, h, N, g, V = limited_integrate_reduce(fa, fd, G, DE) V = [g] + V g = A.gcd(B) A, B, V = A.quo(g), B.quo(g), [ via.cancel(vid * g, include=True) for via, vid in V ] Q, M = prde_linear_constraints(A, B, V, DE) M, _ = constant_system(M, zeros(M.rows, 1), DE) l = M.nullspace() if M == Matrix() or len(l) > 1: # Continue with param_rischDE() raise NotImplementedError("param_rischDE() is required to solve this " "integral.") elif len(l) == 0: raise NonElementaryIntegralException elif len(l) == 1: # The c1 == 1. In this case, we can assume a normal Risch DE if l[0][0].is_zero: raise NonElementaryIntegralException else: l[0] *= 1 / l[0][0] C = sum([Poly(i, DE.t) * q for (i, q) in zip(l[0], Q)]) # Custom version of rischDE() that uses the already computed # denominator and degree bound from above. B, C, m, alpha, beta = spde(A, B, C, N, DE) y = solve_poly_rde(B, C, m, DE) return ((alpha * y + beta, h), list(l[0][1:])) else: raise NotImplementedError
def test_rank(): m = Matrix([[1, 2], [x, 1 - 1 / x]]) assert m.rank() == 2 n = Matrix(3, 3, range(1, 10)) assert n.rank() == 2 p = zeros(3) assert p.rank() == 0
def add_block(curr_block, block_num, input_der, f_aug, x_aug, last_L): ''' Find the new Lie derivative and create a new block for Oi ''' global verbose dummy = symbols(['dummy'])[0] L_h = curr_block * f_aug extra = zeros(curr_block.shape[0], 1) if input_der: #Modification for accounting for inputs for i in range(block_num - 1): if i < input_der.shape[1] - 1: lo_u = input_der[:, i] hi_u = input_der[:, i + 1] lo_u = lo_u.subs(0, dummy) if all([True if i == 0 or i == dummy else False for i in lo_u]): continue extra_ = last_L.jacobian(Matrix(lo_u)) * hi_u extra += extra_ else: break last_L = L_h + extra new_block = last_L.jacobian(x_aug) if verbose: print(new_block) return new_block, last_L
def solve_lin_sys(eqs, ring): """Solve a system of linear equations. """ assert ring.domain.has_Field # transform from equations to matrix form xs = ring.gens M = zeros(len(eqs), len(xs)+1, cls=RawMatrix) for j, e_j in enumerate(eqs): for i, x_i in enumerate(xs): M[j, i] = e_j.coeff(x_i) M[j, -1] = -e_j.coeff(1) eqs = M # solve by row-reduction echelon, pivots = eqs.rref(iszerofunc=lambda x: not x, simplify=lambda x: x) # construct the returnable form of the solutions if pivots[-1] == len(xs): return None elif len(pivots) == len(xs): sol = [ ring.ground_new(s) for s in echelon[:, -1] ] return dict(zip(xs, sol)) else: sols = {} for i, p in enumerate(pivots): vect = RawMatrix([ [-x] for x in xs[p+1:] ] + [[ring.one]]) sols[xs[p]] = (echelon[i, p+1:]*vect)[0] return sols
def hat6(xi): xi_hat = zeros(4, 4) v = xi[0:3, 0] w = xi[3:6, 0] xi_hat[0:3, 0:3] = hat3(w) xi_hat[0:3, 3] = v return xi_hat
def limited_integrate(fa, fd, G, DE): """ Solves the limited integration problem: f = Dv + Sum(ci*wi, (i, 1, n)) """ fa, fd = fa*Poly(1/fd.LC(), DE.t), fd.monic() A, B, h, N, g, V = limited_integrate_reduce(fa, fd, G, DE) V = [g] + V g = A.gcd(B) A, B, V = A.quo(g), B.quo(g), [via.cancel(vid*g, include=True) for via, vid in V] Q, M = prde_linear_constraints(A, B, V, DE) M, _ = constant_system(M, zeros(M.rows, 1), DE) l = M.nullspace() if M == Matrix() or len(l) > 1: # Continue with param_rischDE() raise NotImplementedError("param_rischDE() is required to solve this " "integral.") elif len(l) == 0: raise NonElementaryIntegralException elif len(l) == 1: # The c1 == 1. In this case, we can assume a normal Risch DE if l[0][0].is_zero: raise NonElementaryIntegralException else: l[0] *= 1/l[0][0] C = sum([Poly(i, DE.t)*q for (i, q) in zip(l[0], Q)]) # Custom version of rischDE() that uses the already computed # denominator and degree bound from above. B, C, m, alpha, beta = spde(A, B, C, N, DE) y = solve_poly_rde(B, C, m, DE) return ((alpha*y + beta, h), list(l[0][1:])) else: raise NotImplementedError
def param_rischDE(fa, fd, G, DE): """ Solve a Parametric Risch Differential Equation: Dy + f*y == Sum(ci*Gi, (i, 1, m)). """ _, (fa, fd) = weak_normalizer(fa, fd, DE) a, (ba, bd), G, hn = prde_normal_denom(ga, gd, G, DE) A, B, G, hs = prde_special_denom(a, ba, bd, G, DE) g = gcd(A, B) A, B, G = A.quo(g), B.quo(g), [gia.cancel(gid*g, include=True) for gia, gid in G] Q, M = prde_linear_constraints(A, B, G, DE) M, _ = constant_system(M, zeros(M.rows, 1), DE) # Reduce number of constants at this point try: # Similar to rischDE(), we try oo, even though it might lead to # non-termination when there is no solution. At least for prde_spde, # it will always terminate no matter what n is. n = bound_degree(A, B, G, DE, parametric=True) except NotImplementedError: # Useful for debugging: # import warnings # warnings.warn("param_rischDE: Proceeding with n = oo; may cause " # "non-termination.") n = oo A, B, Q, R, n1 = prde_spde(A, B, Q, n, DE)
def test_is_zero(): assert PropertiesOnlyMatrix(0, 0, []).is_zero assert PropertiesOnlyMatrix([[0, 0], [0, 0]]).is_zero assert PropertiesOnlyMatrix(zeros(3, 4)).is_zero assert not PropertiesOnlyMatrix(eye(3)).is_zero assert PropertiesOnlyMatrix([[x, 0], [0, 0]]).is_zero == None assert PropertiesOnlyMatrix([[x, 1], [0, 0]]).is_zero == False a = Symbol('a', nonzero=True) assert PropertiesOnlyMatrix([[a, 0], [0, 0]]).is_zero == False
def matrix_to_zero(e): """Convert a zero matrix to the scalar zero.""" if isinstance(e, Matrix): if zeros(*e.shape) == e: e = Integer(0) elif isinstance(e, numpy_ndarray): e = _numpy_matrix_to_zero(e) elif isinstance(e, scipy_sparse_matrix): e = _scipy_sparse_matrix_to_zero(e) return e
def apply_single_operation(self, operation): if self.sym: final_dens_matr = mat.zeros(2**self.number_qubits) trans_list = [(oper*self.current_state.density_matrix)*(quant.Dagger(oper)) for oper in operation] for trans_matrix in trans_list: final_dens_matr += trans_matrix self.current_state.density_matrix = final_dens_matr else: trans_list = [(oper*self.current_state.density_matrix)*(oper.H) for oper in operation] self.current_state.density_matrix = sum(trans_list)
def eqs_to_matrix(eqs, ring): """Transform from equations to matrix form. """ xs = ring.gens M = zeros(len(eqs), len(xs)+1, cls=RawMatrix) for j, e_j in enumerate(eqs): for i, x_i in enumerate(xs): M[j, i] = e_j.coeff(x_i) M[j, -1] = -e_j.coeff(1) return M
def matrix_zeros(m, n, **options): """"Get a zeros matrix for a given format.""" format = options.get('format', 'sympy') dtype = options.get('dtype', 'float64') spmatrix = options.get('spmatrix', 'csr') if format == 'sympy': return zeros(m, n) elif format == 'numpy': return _numpy_zeros(m, n, **options) elif format == 'scipy.sparse': return _scipy_sparse_zeros(m, n, **options) raise NotImplementedError('Invaild format: %r' % format)
def prde_no_cancel_b_small(b, Q, n, DE): """ Parametric Poly Risch Differential Equation - No cancellation: deg(b) small enough. Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, returns h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and Dq + b*q == Sum(ci*qi, (i, 1, m)) then q = Sum(dj*hj, (j, 1, r)) where d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. """ m = len(Q) H = [Poly(0, DE.t)]*m for N in xrange(n, 0, -1): # [n, ..., 1] for i in range(m): si = Q[i].nth(N + DE.d.degree(DE.t) - 1)/(N*DE.d.LC()) sitn = Poly(si*DE.t**N, DE.t) H[i] = H[i] + sitn Q[i] = Q[i] - derivation(sitn, DE) - b*sitn if b.degree(DE.t) > 0: for i in range(m): si = Poly(Q[i].nth(b.degree(DE.t))/b.LC(), DE.t) H[i] = H[i] + si Q[i] = Q[i] - derivation(si, DE) - b*si if all(qi.is_zero for qi in Q): dc = -1 M = Matrix() else: dc = max([qi.degree(DE.t) for qi in Q]) M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i)) A, u = constant_system(M, zeros(dc + 1, 1), DE) c = eye(m) A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c)) return (H, A) else: # TODO: implement this (requires recursive param_rischDE() call) raise NotImplementedError
def _get_possible_outcomes(m, bits): """Get the possible states that can be produced in a measurement. Parameters ---------- m : Matrix The matrix representing the state of the system. bits : tuple, list Which bits will be measured. Returns ------- result : list The list of possible states which can occur given this measurement. These are un-normalized so we can derive the probability of finding this state by taking the inner product with itself """ # This is filled with loads of dirty binary tricks...You have been warned size = max(m.shape) # Max of shape to account for bra or ket nqubits = int(math.log(size, 2) + .1) # Number of qubits possible # Make the output states and put in output_matrices, nothing in them now. # Each state will represent a possible outcome of the measurement # Thus, output_matrices[0] is the matrix which we get when all measured # bits return 0. and output_matrices[1] is the matrix for only the 0th # bit being true output_matrices = [] for i in range(1 << len(bits)): output_matrices.append(zeros(2**nqubits, 1)) # Bitmasks will help sort how to determine possible outcomes. # When the bit mask is and-ed with a matrix-index, # it will determine which state that index belongs to bit_masks = [] for bit in bits: bit_masks.append(1 << bit) # Make possible outcome states for i in range(2**nqubits): trueness = 0 # This tells us to which output_matrix this value belongs # Find trueness for j in range(len(bit_masks)): if i & bit_masks[j]: trueness += j + 1 # Put the value in the correct output matrix output_matrices[trueness][i] = m[i] return output_matrices
def _computeBirthDeathVector(self): # holder self._birthDeathVector = zeros(self._numState, 1) # A = self._birthDeathVector # go through all the transition objects for bdObj in self._birthDeathList: fromIndex, toIndex, eqn = self._unrollTransition(bdObj) for i in fromIndex: if bdObj.getTransitionType() is TransitionType.B: self._birthDeathVector[i] += eqn elif bdObj.getTransitionType() is TransitionType.D: self._birthDeathVector[i] -= eqn return self._birthDeathVector
def _computeOdeVector(self): # we are only testing it here because we want to be flexible and # allow the end user to input more state than initially desired if len(self._odeList) <= self._numState: self._ode = zeros(self._numState, 1) for transObj in self._odeList: fromIndex, toIndex, eqn = self._unrollTransition(transObj) if len(fromIndex) > 1: raise InputError("An explicit ode cannot describe more than a single state") else: self._ode[fromIndex[0]] = eqn else: raise InputError("The total number of ode is "+str(len(self._odeList))+ " where the number of state is "+str(self._numState)) return None
def prde_cancel_liouvillian(b, Q, n, DE): """ Pg, 237. """ H = [] # Why use DecrementLevel? Below line answers that: # Assuming that we can solve such problems over 'k' (not k[t]) if DE.case == 'primitive': with DecrementLevel(DE): ba, bd = frac_in(b, DE.t, field=True) for i in range(n, -1, -1): if DE.case == 'exp': # this re-checking can be avoided with DecrementLevel(DE): ba, bd = frac_in(b + i*derivation(DE.t, DE)/DE.t, DE.t, field=True) with DecrementLevel(DE): Qy = [frac_in(q.nth(i), DE.t, field=True) for q in Q] fi, Ai = param_rischDE(ba, bd, Qy, DE) fi = [Poly(fa.as_expr()/fd.as_expr(), DE.t, field=True) for fa, fd in fi] ri = len(fi) if i == n: M = Ai else: M = Ai.col_join(M.row_join(zeros(M.rows, ri))) Fi, hi = [None]*ri, [None]*ri # from eq. on top of p.238 (unnumbered) for j in range(ri): hji = fi[j]*DE.t**i hi[j] = hji # building up Sum(djn*(D(fjn*t^n) - b*fjnt^n)) Fi[j] = -(derivation(hji, DE) - b*hji) H += hi # in the next loop instead of Q it has # to be Q + Fi taking its place Q = Q + Fi return (H, M)
def test_applyfunc(): m0 = OperationsOnlyMatrix(eye(3)) assert m0.applyfunc(lambda x: 2*x) == eye(3)*2 assert m0.applyfunc(lambda x: 0) == zeros(3) assert m0.applyfunc(lambda x: 1) == ones(3)
def solve(f, *symbols, **flags): """Solves equations and systems of equations. Currently supported are univariate polynomial, transcendental equations, piecewise combinations thereof and systems of linear and polynomial equations. Input is formed as a single expression or an equation, or an iterable container in case of an equation system. The type of output may vary and depends heavily on the input. For more details refer to more problem specific functions. By default all solutions are simplified to make the output more readable. If this is not the expected behavior (e.g., because of speed issues) set simplified=False in function arguments. To solve equations and systems of equations like recurrence relations or differential equations, use rsolve() or dsolve(), respectively. >>> from sympy import I, solve >>> from sympy.abc import x, y Solve a polynomial equation: >>> solve(x**4-1, x) [1, -1, -I, I] Solve a linear system: >>> solve((x+5*y-2, -3*x+6*y-15), x, y) {x: -3, y: 1} """ def sympit(w): return map(sympify, iff(isinstance(w, (list, tuple, set)), w, [w])) # make f and symbols into lists of sympified quantities # keeping track of how f was passed since if it is a list # a dictionary of results will be returned. bare_f = not isinstance(f, (list, tuple, set)) f, symbols = (sympit(w) for w in [f, symbols]) if any(isinstance(fi, bool) or (fi.is_Relational and not fi.is_Equality) for fi in f): return reduce_inequalities(f, assume=flags.get("assume")) for i, fi in enumerate(f): if fi.is_Equality: f[i] = fi.lhs - fi.rhs if not symbols: # get symbols from equations or supply dummy symbols since # solve(3,x) returns []...though it seems that it should raise some sort of error TODO symbols = set([]) for fi in f: symbols |= fi.atoms(Symbol) or set([Dummy("x")]) symbols = list(symbols) if bare_f: f = f[0] if len(symbols) == 1: if isinstance(symbols[0], (list, tuple, set)): symbols = symbols[0] result = list() # Begin code handling for Function and Derivative instances # Basic idea: store all the passed symbols in symbols_passed, check to see # if any of them are Function or Derivative types, if so, use a dummy # symbol in their place, and set symbol_swapped = True so that other parts # of the code can be aware of the swap. Once all swapping is done, the # continue on with regular solving as usual, and swap back at the end of # the routine, so that whatever was passed in symbols is what is returned. symbols_new = [] symbol_swapped = False symbols_passed = list(symbols) for i, s in enumerate(symbols): if s.is_Symbol: s_new = s elif s.is_Function: symbol_swapped = True s_new = Dummy("F%d" % i) elif s.is_Derivative: symbol_swapped = True s_new = Dummy("D%d" % i) else: raise TypeError("not a Symbol or a Function") symbols_new.append(s_new) if symbol_swapped: swap_back_dict = dict(zip(symbols_new, symbols)) # End code for handling of Function and Derivative instances if not isinstance(f, (tuple, list, set)): # Create a swap dictionary for storing the passed symbols to be solved # for, so that they may be swapped back. if symbol_swapped: swap_dict = zip(symbols, symbols_new) f = f.subs(swap_dict) symbols = symbols_new # Any embedded piecewise functions need to be brought out to the # top level so that the appropriate strategy gets selected. f = piecewise_fold(f) if len(symbols) != 1: result = {} for s in symbols: result[s] = solve(f, s, **flags) if flags.get("simplified", True): for s, r in result.items(): result[s] = map(simplify, r) return result symbol = symbols[0] strategy = guess_solve_strategy(f, symbol) if strategy == GS_POLY: poly = f.as_poly(symbol) if poly is None: raise NotImplementedError("Cannot solve equation " + str(f) + " for " + str(symbol)) # for cubics and quartics, if the flag wasn't set, DON'T do it # by default since the results are quite long. Perhaps one could # base this decision on a certain crtical length of the roots. if poly.degree > 2: flags["simplified"] = flags.get("simplified", False) result = roots(poly, cubics=True, quartics=True).keys() elif strategy == GS_RATIONAL: P, Q = f.as_numer_denom() # TODO: check for Q != 0 result = solve(P, symbol, **flags) elif strategy == GS_POLY_CV_1: args = list(f.args) if isinstance(f, Add): # we must search for a suitable change of variable # collect exponents exponents_denom = list() for arg in args: if isinstance(arg, Pow): exponents_denom.append(arg.exp.q) elif isinstance(arg, Mul): for mul_arg in arg.args: if isinstance(mul_arg, Pow): exponents_denom.append(mul_arg.exp.q) assert len(exponents_denom) > 0 if len(exponents_denom) == 1: m = exponents_denom[0] else: # get the LCM of the denominators m = reduce(ilcm, exponents_denom) # x -> y**m. # we assume positive for simplification purposes t = Dummy("t", positive=True) f_ = f.subs(symbol, t ** m) if guess_solve_strategy(f_, t) != GS_POLY: raise NotImplementedError("Could not convert to a polynomial equation: %s" % f_) cv_sols = solve(f_, t) for sol in cv_sols: result.append(sol ** m) elif isinstance(f, Mul): for mul_arg in args: result.extend(solve(mul_arg, symbol)) elif strategy == GS_POLY_CV_2: m = 0 args = list(f.args) if isinstance(f, Add): for arg in args: if isinstance(arg, Pow): m = min(m, arg.exp) elif isinstance(arg, Mul): for mul_arg in arg.args: if isinstance(mul_arg, Pow): m = min(m, mul_arg.exp) elif isinstance(f, Mul): for mul_arg in args: if isinstance(mul_arg, Pow): m = min(m, mul_arg.exp) f1 = simplify(f * symbol ** (-m)) result = solve(f1, symbol) # TODO: we might have introduced unwanted solutions # when multiplied by x**-m elif strategy == GS_PIECEWISE: result = set() for expr, cond in f.args: candidates = solve(expr, *symbols) if isinstance(cond, bool) or cond.is_Number: if not cond: continue # Only include solutions that do not match the condition # of any of the other pieces. for candidate in candidates: matches_other_piece = False for other_expr, other_cond in f.args: if isinstance(other_cond, bool) or other_cond.is_Number: continue if bool(other_cond.subs(symbol, candidate)): matches_other_piece = True break if not matches_other_piece: result.add(candidate) else: for candidate in candidates: if bool(cond.subs(symbol, candidate)): result.add(candidate) result = list(result) elif strategy == GS_TRANSCENDENTAL: # a, b = f.as_numer_denom() # Let's throw away the denominator for now. When we have robust # assumptions, it should be checked, that for the solution, # b!=0. result = tsolve(f, *symbols) elif strategy == -1: raise ValueError("Could not parse expression %s" % f) else: raise NotImplementedError("No algorithms are implemented to solve equation %s" % f) # This symbol swap should not be necessary for the single symbol case: if you've # solved for the symbol the it will not appear in the solution. Right now, however # ode's are getting solutions for solve (even though they shouldn't be -- see the # swap_back test in test_solvers). if symbol_swapped: result = [ri.subs(swap_back_dict) for ri in result] if flags.get("simplified", True) and strategy != GS_RATIONAL: return map(simplify, result) else: return result else: if not f: return {} else: # Create a swap dictionary for storing the passed symbols to be # solved for, so that they may be swapped back. if symbol_swapped: swap_dict = zip(symbols, symbols_new) f = [fi.subs(swap_dict) for fi in f] symbols = symbols_new polys = [] for g in f: poly = g.as_poly(*symbols) if poly is not None: polys.append(poly) else: raise NotImplementedError() if all(p.is_linear for p in polys): n, m = len(f), len(symbols) matrix = zeros((n, m + 1)) for i, poly in enumerate(polys): for monom, coeff in poly.terms(): try: j = list(monom).index(1) matrix[i, j] = coeff except ValueError: matrix[i, m] = -coeff soln = solve_linear_system(matrix, *symbols, **flags) else: soln = solve_poly_system(polys) # Use swap_dict to ensure we return the same type as what was # passed if symbol_swapped: if isinstance(soln, dict): res = {} for k in soln.keys(): res.update({swap_back_dict[k]: soln[k]}) return res else: return soln else: return soln
def _solve(f, *symbols, **flags): """ Return a checked solution for f in terms of one or more of the symbols.""" if not iterable(f): if len(symbols) != 1: soln = None free = f.free_symbols ex = free - set(symbols) if len(ex) == 1: ex = ex.pop() try: # may come back as dict or list (if non-linear) soln = solve_undetermined_coeffs(f, symbols, ex) except NotImplementedError: pass if not soln is None: return soln # find first successful solution failed = [] for s in symbols: n, d = solve_linear(f, x=[s]) if n.is_Symbol: soln = {n: cancel(d)} return soln failed.append(s) for s in failed: try: soln = _solve(f, s, **flags) return soln except NotImplementedError: pass else: msg = "No algorithms are implemented to solve equation %s" raise NotImplementedError(msg % f) symbol = symbols[0] # first see if it really depends on symbol and whether there # is a linear solution f_num, sol = solve_linear(f, x=symbols) if not symbol in f_num.free_symbols: return [] elif f_num.is_Symbol: return [cancel(sol)] strategy = guess_solve_strategy(f, symbol) result = False # no solution was obtained if strategy == GS_POLY: poly = f.as_poly(symbol) if poly is None: msg = "Cannot solve equation %s for %s" % (f, symbol) else: # for cubics and quartics, if the flag wasn't set, DON'T do it # by default since the results are quite long. Perhaps one could # base this decision on a certain critical length of the roots. if poly.degree() > 2: flags['simplified'] = flags.get('simplified', False) result = roots(poly, cubics=True, quartics=True).keys() elif strategy == GS_RATIONAL: P, _ = f.as_numer_denom() dens = denoms(f, x=symbols) try: soln = _solve(P, symbol, **flags) except NotImplementedError: msg = "Cannot solve equation %s for %s" % (P, symbol) result = [] else: if dens: # reject any result that makes any denom. affirmatively 0; # if in doubt, keep it result = [s for s in soln if all(not checksol(den, {symbol: s}, **flags) for den in dens)] else: result = soln elif strategy == GS_POLY_CV_1: args = list(f.args) if isinstance(f, Pow): result = _solve(args[0], symbol, **flags) elif isinstance(f, Add): # we must search for a suitable change of variables # collect exponents exponents_denom = list() for arg in args: if isinstance(arg, Pow): exponents_denom.append(arg.exp.q) elif isinstance(arg, Mul): for mul_arg in arg.args: if isinstance(mul_arg, Pow): exponents_denom.append(mul_arg.exp.q) assert len(exponents_denom) > 0 if len(exponents_denom) == 1: m = exponents_denom[0] else: # get the LCM of the denominators m = reduce(ilcm, exponents_denom) # x -> y**m. # we assume positive for simplification purposes t = Dummy('t', positive=True) f_ = f.subs(symbol, t**m) if guess_solve_strategy(f_, t) != GS_POLY: msg = "Could not convert to a polynomial equation: %s" % f_ result = [] else: soln = [s**m for s in _solve(f_, t)] # we might have introduced solutions from another branch # when changing variables; check and keep solutions # unless they definitely aren't a solution result = [s for s in soln if checksol(f, {symbol: s}, **flags) is not False] elif isinstance(f, Mul): result = [] for m in f.args: result.extend(_solve(m, symbol, **flags) or []) elif strategy == GS_POLY_CV_2: m = 0 args = list(f.args) if isinstance(f, Add): for arg in args: if isinstance(arg, Pow): m = min(m, arg.exp) elif isinstance(arg, Mul): for mul_arg in arg.args: if isinstance(mul_arg, Pow): m = min(m, mul_arg.exp) elif isinstance(f, Mul): for mul_arg in args: if isinstance(mul_arg, Pow): m = min(m, mul_arg.exp) if m and m != 1: f_ = simplify(f*symbol**(-m)) try: sols = _solve(f_, symbol) except NotImplementedError: msg = 'Could not solve %s for %s' % (f_, symbol) else: # we might have introduced unwanted solutions # when multiplying by x**-m; check and keep solutions # unless they definitely aren't a solution if sols: result = [s for s in sols if checksol(f, {symbol: s}, **flags) is not False] else: msg = 'CV_2 calculated %d but it should have been other than 0 or 1' % m elif strategy == GS_PIECEWISE: result = set() for expr, cond in f.args: candidates = _solve(expr, *symbols) if isinstance(cond, bool) or cond.is_Number: if not cond: continue # Only include solutions that do not match the condition # of any of the other pieces. for candidate in candidates: matches_other_piece = False for other_expr, other_cond in f.args: if isinstance(other_cond, bool) \ or other_cond.is_Number: continue if bool(other_cond.subs(symbol, candidate)): matches_other_piece = True break if not matches_other_piece: result.add(candidate) else: for candidate in candidates: if bool(cond.subs(symbol, candidate)): result.add(candidate) result = list(result) elif strategy == -1: raise ValueError('Could not parse expression %s' % f) # this is the fallback for not getting any other solution if result is False or strategy == GS_TRANSCENDENTAL: soln = tsolve(f_num, symbol) dens = denoms(f, x=symbols) if not dens: result = soln else: # reject any result that makes any denom. affirmatively 0; # if in doubt, keep it result = [s for s in soln if all(not checksol(den, {symbol: s}, **flags) for den in dens)] if result is False: raise NotImplementedError(msg + "\nNo algorithms are implemented to solve equation %s" % f) if flags.get('simplified', True) and strategy != GS_RATIONAL: result = map(simplify, result) return result else: if not f: return [] else: polys = [] for g in f: poly = g.as_poly(*symbols, **{'extension': True}) if poly is not None: polys.append(poly) else: raise NotImplementedError() if all(p.is_linear for p in polys): n, m = len(f), len(symbols) matrix = zeros((n, m + 1)) for i, poly in enumerate(polys): for monom, coeff in poly.terms(): try: j = list(monom).index(1) matrix[i, j] = coeff except ValueError: matrix[i, m] = -coeff # a dictionary of symbols: values or None result = solve_linear_system(matrix, *symbols, **flags) return result else: # a list of tuples, T, where T[i] [j] corresponds to the ith solution for symbols[j] result = solve_poly_system(polys) return result
def solve(f, *symbols, **flags): """Solves equations and systems of equations. Currently supported are univariate polynomial and transcendental equations and systems of linear and polynomial equations. Input is formed as a single expression or an equation, or an iterable container in case of an equation system. The type of output may vary and depends heavily on the input. For more details refer to more problem specific functions. By default all solutions are simplified to make the output more readable. If this is not the expected behavior, eg. because of speed issues, set simplified=False in function arguments. To solve equations and systems of equations of other kind, eg. recurrence relations of differential equations use rsolve() or dsolve() functions respectively. >>> from sympy import * >>> x,y = symbols('xy') Solve a polynomial equation: >>> solve(x**4-1, x) [1, -1, -I, I] Solve a linear system: >>> solve((x+5*y-2, -3*x+6*y-15), x, y) {x: -3, y: 1} """ if not symbols: raise ValueError('no symbols were given') if len(symbols) == 1: if isinstance(symbols[0], (list, tuple, set)): symbols = symbols[0] symbols = map(sympify, symbols) result = list() # Begin code handling for Function and Derivative instances # Basic idea: store all the passed symbols in symbols_passed, check to see # if any of them are Function or Derivative types, if so, use a dummy # symbol in their place, and set symbol_swapped = True so that other parts # of the code can be aware of the swap. Once all swapping is done, the # continue on with regular solving as usual, and swap back at the end of # the routine, so that whatever was passed in symbols is what is returned. symbols_new = [] symbol_swapped = False if isinstance(symbols, (list, tuple)): symbols_passed = symbols[:] elif isinstance(symbols, set): symbols_passed = list(symbols) i = 0 for s in symbols: if s.is_Symbol: s_new = s elif s.is_Function: symbol_swapped = True s_new = Symbol('F%d' % i, dummy=True) elif s.is_Derivative: symbol_swapped = True s_new = Symbol('D%d' % i, dummy=True) else: raise TypeError('not a Symbol or a Function') symbols_new.append(s_new) i += 1 if symbol_swapped: swap_back_dict = dict(zip(symbols_new, symbols)) # End code for handling of Function and Derivative instances if not isinstance(f, (tuple, list, set)): f = sympify(f) # Create a swap dictionary for storing the passed symbols to be solved # for, so that they may be swapped back. if symbol_swapped: swap_dict = zip(symbols, symbols_new) f = f.subs(swap_dict) symbols = symbols_new if isinstance(f, Equality): f = f.lhs - f.rhs if len(symbols) != 1: raise NotImplementedError('multivariate equation') symbol = symbols[0] strategy = guess_solve_strategy(f, symbol) if strategy == GS_POLY: poly = f.as_poly( symbol ) assert poly is not None result = roots(poly, cubics=True, quartics=True).keys() elif strategy == GS_RATIONAL: P, Q = f.as_numer_denom() #TODO: check for Q != 0 return solve(P, symbol, **flags) elif strategy == GS_POLY_CV_1: args = list(f.args) if isinstance(f, Add): # we must search for a suitable change of variable # collect exponents exponents_denom = list() for arg in args: if isinstance(arg, Pow): exponents_denom.append(arg.exp.q) elif isinstance(arg, Mul): for mul_arg in arg.args: if isinstance(mul_arg, Pow): exponents_denom.append(mul_arg.exp.q) assert len(exponents_denom) > 0 if len(exponents_denom) == 1: m = exponents_denom[0] else: # get the GCD of the denominators m = ilcm(*exponents_denom) # x -> y**m. # we assume positive for simplification purposes t = Symbol('t', positive=True, dummy=True) f_ = f.subs(symbol, t**m) if guess_solve_strategy(f_, t) != GS_POLY: raise TypeError("Could not convert to a polynomial equation: %s" % f_) cv_sols = solve(f_, t) for sol in cv_sols: result.append(sol**m) elif isinstance(f, Mul): for mul_arg in args: result.extend(solve(mul_arg, symbol)) elif strategy == GS_POLY_CV_2: m = 0 args = list(f.args) if isinstance(f, Add): for arg in args: if isinstance(arg, Pow): m = min(m, arg.exp) elif isinstance(arg, Mul): for mul_arg in arg.args: if isinstance(mul_arg, Pow): m = min(m, mul_arg.exp) elif isinstance(f, Mul): for mul_arg in args: if isinstance(mul_arg, Pow): m = min(m, mul_arg.exp) f1 = simplify(f*symbol**(-m)) result = solve(f1, symbol) # TODO: we might have introduced unwanted solutions # when multiplied by x**-m elif strategy == GS_TRANSCENDENTAL: #a, b = f.as_numer_denom() # Let's throw away the denominator for now. When we have robust # assumptions, it should be checked, that for the solution, # b!=0. result = tsolve(f, *symbols) elif strategy == -1: raise ValueError('Could not parse expression %s' % f) else: raise NotImplementedError("No algorithms are implemented to solve equation %s" % f) if flags.get('simplified', True): return map(simplify, result) else: return result else: if not f: return {} else: # Create a swap dictionary for storing the passed symbols to be # solved for, so that they may be swapped back. if symbol_swapped: swap_dict = zip(symbols, symbols_new) f = [fi.subs(swap_dict) for fi in f] symbols = symbols_new polys = [] for g in f: g = sympify(g) if isinstance(g, Equality): g = g.lhs - g.rhs poly = g.as_poly(*symbols) if poly is not None: polys.append(poly) else: raise NotImplementedError() if all(p.is_linear for p in polys): n, m = len(f), len(symbols) matrix = zeros((n, m + 1)) for i, poly in enumerate(polys): for coeff, monom in poly.iter_terms(): try: j = list(monom).index(1) matrix[i, j] = coeff except ValueError: matrix[i, m] = -coeff soln = solve_linear_system(matrix, *symbols, **flags) else: soln = solve_poly_system(polys) # Use swap_dict to ensure we return the same type as what was # passed if symbol_swapped: if isinstance(soln, dict): res = {} for k in soln.keys(): res.update({swap_back_dict[k]: soln[k]}) return res else: return soln else: return soln
def test_sparse_zeros_sparse_eye(): assert SparseMatrix.eye(3) == eye(3, cls=SparseMatrix) assert len(SparseMatrix.eye(3)._smat) == 3 assert SparseMatrix.zeros(3) == zeros(3, cls=SparseMatrix) assert len(SparseMatrix.zeros(3)._smat) == 0