예제 #1
0
def SpreSmSp(op):
    opN = op.shape[0]
    opSM = sm.SparseMatrix(op)
    #This is essentially just a sparse block-matrix
    SpreS = sm.SparseMatrix(opN**2, opN**2, {(opN * k, opN * k): opSM
                                             for k in range(opN)})
    return SpreS
예제 #2
0
    def matrices(self):
        """
        Let M be the number of possible states. Returns N x M State matrix
        and M x M transition matrix
        Outputs:
            S: N x M state matrix
            T: M x M transition matrix
            V: M x M transition matrix weighted by transition "speeds" (+1 move right, -1 move left)
        """
        states = self.enum_states()
        M = len(states)
        transitions_speeds = [(s, self.transitions(State(s)),
                               self.speeds(State(s))) for s in states]
        S = np.zeros((self.N, M))
        if self.is_symbolic() == True:
            T = sympy.SparseMatrix(M, M, 0)
            V = sympy.SparseMatrix(M, M, 0)
        else:
            T = sparse.csr_matrix((M, M))
            V = sparse.csr_matrix((M, M))

        k = 0
        for s, t, v in transitions_speeds:
            i = self.state_index(s)
            S[:, i] = State(s).values
            for r in t:
                j = self.state_index(r)
                T[j, i] = t[r]
                if r in v:
                    V[j, i] = v[r]
                k += 1
        V = T.multiply(V)  # speed weighted by probabilities

        return S, T, V
예제 #3
0
def SpostSmSp(op):
    N = op.shape[0]

    dct = {(N * l, N * k): sm.SparseMatrix(N, N, {(i, i): op[k, l]
                                                  for i in range(N)})
           for k, l in product(range(N), repeat=2)}
    SpostS = sm.SparseMatrix(N**2, N**2, dct)
    return SpostS
예제 #4
0
def makeMESymb(H_L,
               c_opL=[],
               e_opL=[],
               rhoS=None,
               bReturnMatrixEquation=False):
    """Take the Hamiltonia,coeficients and return density matrix evolution
    expressions Format for H: [H0, [coeff_sym1, H1], [coeff_sym2, H2] ...]"""
    #print('makeMESymb enter', flush=True)
    #pdb.set_trace()
    # Make the liouvillian-----------------------------------
    H0 = H_L.pop(0)
    H0 = sm.SparseMatrix(H0)
    Nstates = H0.shape[0]

    if rhoS is None:
        rhoS = getRhoS(Nstates)

    # Construct Hamiltonian part
    L = liouvillianS(H0)
    for el in H_L:
        if np.iterable(el) and not type(el) == q.Qobj and not type(
                el) == np.matrix and not type(el) == np.array:
            sym, op = el
        else:
            print(
                "no coefficient for a hamiltonian element. Will assume it's 1")
            sym = 1.
            op = sm.SparseMatrix(el)
        L += sym * liouvillianS(op)

    for el in c_opL[:]:
        if np.iterable(el) and not type(el) == q.Qobj and not type(
                el) == np.matrix and not type(el) == np.array:
            coef, op = el
        else:
            coef = 1.
            op = el
        op = sm.SparseMatrix(op)
        L += coef * liouvillianS(None, cOpL=[op])

    # Get drho_dt
    drho_dtS = (L * rhoS.reshape(Nstates**2, 1)).reshape(
        Nstates, Nstates)  # *sm.Matrix(rs)
    drho_dtS.simplify()

    e_op_outL = []
    for op in e_opL:
        ex = sm.Trace(rhoS * op).doit(
        )  # np.sum(array(H1[off_diag_ind])*array(rhoS)[off_diag_ind]).subs(Esym,1)
        ex = ex.simplify()
        e_op_outL.append(ex)
    eq = sm.Eq(rhoS, drho_dtS)
    if bReturnMatrixEquation:  #returns the full matrix
        return eq, e_op_outL
    lhsL, rhsL = seperate_DM_equation(eq)  #otherwise just the evolving bits
    return lhsL, rhsL, e_op_outL
    def compute_Jwx(self):
        if False:
            self.Jwx = sy.SparseMatrix(
                sy.zeros(self.N + 1, self.Nxi * self.N - self.N_lambda))
            self.Jwx[0:self.N + 1,
                     0:self.N + 1] = sy.SparseMatrix(sy.eye(self.N + 1))

        # terminal dissipation
        self.Jwx = sy.zeros(1, self.Nxi * self.N - self.N_lambda)
        self.Jwx[0, 2 * self.N - self.N_lambda - 1] = 1
        print(self.Jwx)
 def compute_Jyx(self):
     self.Jyx = sy.SparseMatrix(
         sy.zeros(self.N + 2, self.Nx - self.N_lambda))
     self.Jyx[0, 0] = -1
     self.Jyx[1, 2 * self.N - self.N_lambda - 1] = 1
     self.Jyx[2::, 2 * self.N - self.N_lambda:3 * self.N -
              self.N_lambda] = -1 * sy.eye(self.N)
예제 #7
0
 def pd(self):
     output = sympify(0)
     for w, z in zip(self.w, self.z):
         output += w * z
     output += sympy.SparseMatrix(self.a()).dot(
         matvecprod(self.R(), self.a()))
     return output
예제 #8
0
 def _print_Identity(self, expr):
     if isinstance(expr.rows, Integer) or isinstance(
             expr.rows, IntegerConstant):
         return self._print(sympy.SparseMatrix(expr))
     else:
         return "Matrix({var_size}, shape = identity)".format(
             var_size=self._print(expr.rows))
예제 #9
0
 def compute_variableChange(self):
     ''' Goes from a DAE-PHS formulation to a constrainted pHs formulation'''
     self.compute_B()
     self.compute_B_left_annihilator()
     self.M = sy.SparseMatrix(sy.zeros(self.Nx, self.Nx))
     self.M[0:self.Nx- self.N_lambda,::]       = self.annul_b
     self.M[self.Nx- self.N_lambda::, ::] = (self.b.T*self.b).inv()*self.b.T
예제 #10
0
def matrix_coeff(m, s):
    """returns the sp.Matrix valued coefficients N_i in m(x) = N_1 * x**(n-1) + N_2 * x**(n-2) + .. + N_deg(m)

    m : sp.Matrix
        sp.Matrix to get coefficient matrices from
    s :
        sp.Symbol to compute coefficient list (coefficients are ambiguous for expressins with multiple symbols)
    """

    m_deg = matrix_degree(m, s)
    res = [sp.zeros(m.shape[0], m.shape[1])] * (m_deg + 1)

    for r, row in enumerate(m.tolist()):
        for e, entry in enumerate(row):

            entry_coeff_list = sp.Poly(entry, s).all_coeffs()
            if sp.simplify(entry) == 0:
                coeff_deg = 0
            else:
                coeff_deg = sp.degree(entry, s)

            for c, coeff in enumerate(entry_coeff_list):
                res[c + m_deg - coeff_deg] += \
                    sp.SparseMatrix(m.shape[0], m.shape[1], {(r, e): 1}) * coeff
    return res
예제 #11
0
    def compute_B_left_annihilator(self):
        self.annul_b = sy.SparseMatrix(sy.zeros(self.Nx-self.N_lambda, self.Nx))

        self.annul_b[0,0] = 1
        self.annul_b[self.N::, self.N + self.N_lambda::] = sy.eye(3*self.N+1)
        for i in range(1,self.N_lambda+1):
            self.annul_b[i, 2*i-1] = 1 
            self.annul_b[i, 2*i] = 1
예제 #12
0
 def get_all_Jacobians(self):
     size = len(self.frames)
     # j shape will always be (6 x size)
     J_rows = 6 * size
     J_cols = size
     J = sym.SparseMatrix(J_rows, J_cols, [0] * J_rows * J_cols)
     for i in range(size):
         J[i * 6:(i + 1) * 6, 0:size] = self.get_Jacobian(i + 1)
     return J
예제 #13
0
    def compute_Jxx(self):
        self.Jxx = sy.SparseMatrix(sy.zeros(self.Nx))

        for i in range(self.N):
            self.Jxx[self.Nxi*i:self.Nxi*(i+1), self.Nxi*i:self.Nxi*(i+1)] = self.compute_Ji(i+1)
            
        self.compute_permutation_matrix()
        self.compute_variableChange()
        self.Jxx = self.M*self.P * self.Jxx * self.P.T * self.M.T
        self.Jxx = self.Jxx[0:self.Nx-self.N_lambda, 0:self.Nx-self.N_lambda]
예제 #14
0
 def __init__(self, model, with_jacobian=False, cleanup=True, _logger=None):
     self.with_jacobian = with_jacobian
     self.cleanup = cleanup
     self._logger = _logger
     expr_dynamic = model.expressions_dynamic(include_derived=True)
     expr_constant = model.expressions_constant(include_derived=True)
     self.y = sympy.MatrixSymbol('y', len(model.species), 1)
     self.p = sympy.MatrixSymbol('p', len(model.parameters_all()), 1)
     self.e = sympy.MatrixSymbol('e', len(expr_constant), 1)
     self.o = sympy.MatrixSymbol('o', len(model.observables), 1)
     # Parameters symbols. We also need this independently of all_subs.
     param_subs = dict(zip(model.parameters_all(), self.p))
     # All substitution rules we need to apply to the reaction expressions.
     all_subs = param_subs.copy()
     # Species symbols.
     all_subs.update({
         sympy.Symbol('__s%d' % i): self.y[i]
         for i in range(len(model.species))
     })
     # Observables symbols.
     all_subs.update(dict(zip(model.observables, self.o)))
     # Constant expressions symbols.
     all_subs.update(dict(zip(expr_constant, self.e)))
     # Dynamic expressions (expanded).
     all_subs.update({e: e.expand_expr() for e in expr_dynamic})
     self.kinetics = sympy.Matrix(
         [r['rate'].subs(all_subs) for r in model.reactions])
     if with_jacobian:
         # The Jacobian can be quite large but it's extremely sparse. We can
         # obtain a sparse representation by making a SparseMatrix copy of
         # the kinetics vector and computing the Jacobian on that.
         kinetics_sparse = sympy.SparseMatrix(self.kinetics)
         # Rather than substitute all the observables linear-combination-of-
         # species expressions into the kinetics and then compute the
         # Jacobian, we can use the total derivative / chain rule to
         # simplify things. The final jacobian of the kinetics must be
         # computed as jac(y) + jac(o) * observables_matrix.
         self._logger.debug("Computing Jacobian matrices")
         self.kinetics_jacobian_y = kinetics_sparse.jacobian(self.y)
         self.kinetics_jacobian_o = kinetics_sparse.jacobian(self.o)
     obs_matrix = scipy.sparse.lil_matrix(
         (len(model.observables), len(model.species)), dtype=np.int64)
     for i, obs in enumerate(model.observables):
         obs_matrix[i, obs.species] = obs.coefficients
     self.observables_matrix = obs_matrix.tocsr()
     self.stoichiometry_matrix = model.stoichiometry_matrix
     self.model_name = model.name
     self._expressions_constant = [
         e.expand_expr().xreplace(param_subs) for e in expr_constant
     ]
     self._work_path = None
     self._expressions_constant_fn = None
     self._rhs_fn = None
     self._jacobian_fn = None
예제 #15
0
def hermitian_basis(dim):
    """
    Returns a basis of the hermitian matrices of size ``dim`` that is orthogonal w.r.t. the Frobenius scalar product.

    :param dim: size of the matrices
    :type dim:  int

    Example:

        >>> import kdotp_symmetry as kp
        >>> kp.hermitian_basis(2)
        [Matrix([
        [1, 0],
        [0, 0]]), Matrix([
        [0, 0],
        [0, 1]]), Matrix([
        [0, 1],
        [1, 0]]), Matrix([
        [0, -I],
        [I,  0]])]
    """
    basis = []
    # diagonal entries
    for i in range(dim):
        basis.append(sp.SparseMatrix(dim, dim, {(i, i): 1}))

    # off-diagonal entries
    for i in range(dim):
        for j in range(i + 1, dim):
            # real
            basis.append(sp.SparseMatrix(dim, dim, {(i, j): 1, (j, i): 1}))

            # imag
            basis.append(
                sp.SparseMatrix(dim, dim, {(i, j): -sp.I,
                                           (j, i): sp.I})
            )

    assert len(basis) == dim**2

    return basis
예제 #16
0
 def compute_Q12(self):
     self.Q12 = sy.zeros(self.N_lambda, self.N+1)
     for i in range(self.N_lambda):
         for j in range(self.N+1):
             if i == j:
                 self.Q12[i, j] = -sy.Rational(1,2) * self.mu(i+1)
             if j == i+1:
                 self.Q12[i, j] = sy.Rational(1,2) * self.mu_minus_mu(i+1,i+2)
             if j == i+2:
                 self.Q12[i, j] = sy.Rational(1,2) * self.mu(i+2)
     self.Q12 = sy.SparseMatrix(self.Q12)   
     return self.Q12
예제 #17
0
def liouvillianS(op, cOpL=[]):
    if op is not None:
        L = 1j * (SpreSmSp(op) - SpostSmSp((op)))

    else:
        N = cOpL[0].shape[0]
        #L = np.matrix(np.zeros((N**2,N**2), dtype='object'))
        L = sm.SparseMatrix(N**2, N**2, {})
    for cOp in cOpL:
        #cOp = np.matrix(cOp)
        cdc = cOp.H * cOp
        #cdc = herm_c(cOp)*cOp
        L += SpreSmSp(cOp)*SpostSmSp(cOp.H) -\
            (SpreSmSp(cdc) +SpostSmSp(cdc))/2
    return L
예제 #18
0
def smith_normal_form(matrix, augment=None):
    """Computes the Smith normal form of the given matrix.


    Args:
        matrix:
        augment:

    Returns:
        n x n smith normal form of the matrix.
        Particularly for projection onto the nullspace of M and the orthogonal
        complement that is, for a matrix M,
        P = _smith_normal_form(M) is a projection operator onto the
        nullspace of M

    """

    if augment is not None:
        M = matrix.row_join(augment)
        k = augment.cols
    else:
        M = matrix
        k = 0
    m, n = M.shape
    M = augmented_rref(M, k)

    Mp = sympy.MutableSparseMatrix(n - k, n, {})

    constraints = []
    for row in range(m):
        leading_coeff = -1
        for col in range(row, n - k):
            if M[row, col] != 0:
                leading_coeff = col
                break
        if leading_coeff < 0:
            if not M[row, n - k:].is_zero_matrix:
                constraints.append(sum(M[row, :]))

        else:
            Mp[leading_coeff, :] = M[row, :]

    if augment:
        return Mp[:, :-k], Mp[:, -k:], constraints
    else:
        return Mp, sympy.SparseMatrix(m, k, {}), constraints
예제 #19
0
파일: line.py 프로젝트: yuanzy97/dian
    def compute_param_custom(self):
        """Compute `self.Y` for lines"""
        # Note: this one assumes `self.a1_int` is the indices of `self.a1` in `bus.a`

        dok_y = dict()
        a1_addr = self._dae_address['a1']
        a2_addr = self._dae_address['a2']

        # pylint: disable=maybe-no-member
        for a1, y1, m2, y12 in zip(a1_addr, self.y1, self.m2, self.y12):
            # Need to check if key exist. Otherwise, same multiple `a1` will overwrite the value
            if (a1, a1) not in dok_y.keys():
                dok_y[(a1, a1)] = (y1 + y12) / m2
            else:
                dok_y[(a1, a1)] = dok_y[(a1, a1)] + ((y1 + y12) / m2)

        for a1, a2, y12, mconj in zip(a1_addr, a2_addr, self.y12, self.mconj):
            if (a1, a2) not in dok_y.keys():
                dok_y[(a1, a2)] = -y12 / mconj
            else:
                dok_y[(a1, a2)] = dok_y[(a1, a2)] - y12 / mconj
        for a1, a2, y12, m in zip(a1_addr, a2_addr, self.y12, self.m):
            if (a2, a1) not in dok_y.keys():
                dok_y[(a2, a1)] = -y12 / m
            else:
                dok_y[(a2, a1)] = dok_y[(a2, a1)] - y12 / m
        for a2, y12, y2 in zip(a2_addr, self.y12, self.y2):
            if (a2, a2) not in dok_y.keys():
                dok_y[(a2, a2)] = y12 + y2
            else:
                dok_y[(a2, a2)] = dok_y[(a2, a2)] + (y12 + y2)

        nbus = self.system.bus.n

        self.Y = smp.SparseMatrix(nbus, nbus, dok_y)
        self.Y = smp.Matrix(self.Y)
예제 #20
0
    def processReactions(self):
        """Get reactions from SBML model.

        Arguments:

        Returns:

        Raises:

        """
        reactions = self.sbml.getListOfReactions()
        nr = len(reactions)
        nx = len(self.symbols['species']['name'])
        # stoichiometric matrix
        self.stoichiometricMatrix = sp.SparseMatrix(sp.zeros(nx, nr))
        self.fluxVector = sp.zeros(nr, 1)

        assignment_ids = [
            ass.getId() for ass in self.sbml.getListOfInitialAssignments()
        ]
        rulevars = [
            rule.getVariable() for rule in self.sbml.getListOfRules()
            if rule.getFormula() != ''
        ]

        reaction_ids = [
            reaction.getId() for reaction in reactions if reaction.isSetId()
        ]

        def getElementFromAssignment(element_id):
            assignment = self.sbml.getInitialAssignment(element_id)
            sym = sp.sympify(sbml.formulaToL3String(assignment.getMath()))
            # this is an initial assignment so we need to use
            # initial conditions
            if sym is not None:
                sym = sym.subs(self.symbols['species']['identifier'],
                               self.symbols['species']['value'])
            return sym

        def getElementStoichiometry(element):
            if element.isSetId():
                if element.getId() in assignment_ids:
                    symMath = getElementFromAssignment(element.getId())
                    if symMath is None:
                        symMath = sp.sympify(element.getStoichiometry())
                elif element.getId() in rulevars:
                    return sp.Symbol(element.getId())
                else:
                    # dont put the symbol if it wont get replaced by a
                    # rule
                    symMath = sp.sympify(element.getStoichiometry())
            elif element.isSetStoichiometry():
                symMath = sp.sympify(element.getStoichiometry())
            else:
                return sp.sympify(1.0)
            _check_unsupported_functions(symMath, 'Stoichiometry')
            return symMath

        def isConstant(specie):
            return specie in self.constantSpecies or \
                specie in self.boundaryConditionSpecies

        for reactionIndex, reaction in enumerate(reactions):
            for elementList, sign in [(reaction.getListOfReactants(), -1.0),
                                      (reaction.getListOfProducts(), 1.0)]:
                elements = {}
                for index, element in enumerate(elementList):
                    # we need the index here as we might have multiple elements
                    # for the same species
                    elements[index] = {'species': element.getSpecies()}
                    elements[index]['stoichiometry'] = getElementStoichiometry(
                        element)

                for index in elements.keys():
                    if not isConstant(elements[index]['species']):
                        specieIndex = self.speciesIndex[elements[index]
                                                        ['species']]
                        self.stoichiometricMatrix[specieIndex, reactionIndex] \
                            += sign \
                            * elements[index]['stoichiometry'] \
                            * self.speciesConversionFactor[specieIndex] \
                            / self.speciesCompartment[specieIndex]

            # usage of formulaToL3String ensures that we get "time" as time
            # symbol
            math = sbml.formulaToL3String(reaction.getKineticLaw().getMath())
            try:
                symMath = sp.sympify(math)
            except:
                raise SBMLException(f'Kinetic law "{math}" contains an '
                                    'unsupported expression!')
            _check_unsupported_functions(symMath, 'KineticLaw')
            for r in reactions:
                elements = list(r.getListOfReactants()) \
                           + list(r.getListOfProducts())
                for element in elements:
                    if element.isSetId() & element.isSetStoichiometry():
                        symMath = symMath.subs(
                            sp.sympify(element.getId()),
                            sp.sympify(element.getStoichiometry()))

            self.fluxVector[reactionIndex] = symMath
            if any([
                    str(symbol) in reaction_ids
                    for symbol in self.fluxVector[reactionIndex].free_symbols
            ]):
                raise SBMLException(
                    'Kinetic laws involving reaction ids are currently'
                    ' not supported!')
예제 #21
0
    def system_model(self, control_vars=None):
        """Produces a symbolic model of the system in reduced form.

        In many cases it is useful to have a full description of the system in
        symbolic form, and not just a list of constitutive relations.

        Returns:
            (coordinates, mappings, linear_op, nonlinear_op, constraints)

        This method generates:

            * The model coordinate system (`list`) :math:`x`
            * A mapping (`dict`) between the model coordinates and the
              component coordinates
            * A linear operator (`sympy.Matrix`) :math:`L`
            * A nonlinear operator (`sympy.Matrix`) :math:`F`
            * A list of constraints (`sympy.Matrix`) :math:`G`

        The coordinates are of the form

        .. math::

            x = (dx_0,  dx_1,  \\ldots,  e_0,  f_0, e_1, f_1, \\ldots, x_0,
            x_1, \\ldots, u_0, u_1, \\ldots)

        So that the system obeys the differential-algebraic equation

        .. math::

            Lx + F(x) = 0 \\qquad G(x) =0


        See Also:
            :attr:`BondGraph.basis_vectors`

        """
        mappings, coordinates = inverse_coord_maps(
            *self._build_internal_basis_vectors())
        inv_tm, inv_js, inv_cv = mappings

        network_size = len(inv_js)  # number of ports
        state_size = len(inv_tm)  # number of state space coords
        inout_size = len(inv_cv)
        n = len(coordinates)

        size_tuple = (state_size, network_size, inout_size, n)

        lin_dict = adjacency_to_dict(inv_js, self.bonds, offset=state_size)

        nlin_dict = {}

        try:
            row = max(row + 1 for row, _ in lin_dict.keys())
        except ValueError:
            row = 0

        inverse_port_map = {}

        for port, (cv_e, cv_f) in self._port_map.items():
            inverse_port_map[cv_e] = state_size + 2 * inv_js[port]
            inverse_port_map[cv_f] = state_size + 2 * inv_js[port] + 1

        for component in self.components:
            relations = get_relations_iterator(component, mappings,
                                               coordinates, inverse_port_map)

            for linear, nonlinear in relations:
                lin_dict.update({(row, k): v for k, v in linear.items()})
                nlin_dict.update({(row, 0): nonlinear})
                row += 1

        linear_op = sp.SparseMatrix(row, n, lin_dict)
        nonlinear_op = sp.SparseMatrix(row, 1, nlin_dict)
        coordinates, linear_op, nonlinear_op, constraints = reduce_model(
            linear_op,
            nonlinear_op,
            coordinates,
            size_tuple,
            control_vars=control_vars)

        return coordinates, mappings, linear_op, nonlinear_op, constraints