Пример #1
0
def handle_sum_or_prod(func, name):
    val = convert_mp(func.mp())
    iter_var = convert_expr(func.subeq().equality().expr(0))
    start = convert_expr(func.subeq().equality().expr(1))
    if func.supexpr().expr():  # ^{expr}
        end = convert_expr(func.supexpr().expr())
    else:  # ^atom
        end = convert_atom(func.supexpr().atom())

    if name == "summation":
        return sympy.Sum(val, (iter_var, start, end))
    elif name == "product":
        return sympy.Product(val, (iter_var, start, end))
Пример #2
0
def dtft(xn):
    """离散时间傅里叶变换

    :Parameters:
        - xn: 离散非周期序列,序列只能有1个自变量

    :Returns: 频谱密度函数(周期连续信号),自变量为Omega(用W表示)
    """
    raise Exception("Can't sum from -oo to oo")
    n = tuple(xn.free_symbols)[0]
    W = sy.symbols('W')
    r = (n, -sy.oo, sy.oo)
    xW = sy.Sum(xn * sy.exp(-sy.I * W * n), r)
    return xW
Пример #3
0
 def _initialize_functions(self):
     """
     Build up the nDimensionssymbolic definitions
     """
     # Parameters
     nDimensions= self.constants[self.nDimensions]
     self.position = sp.Matrix([sp.symbols("r_" + str(i)) for i in range(nDimensions)])
     self.r_shift = sp.Matrix([sp.symbols("r_shift" + str(i)) for i in range(nDimensions)])
     self.V_off = sp.Matrix([sp.symbols("V_off_" + str(i)) for i in range(nDimensions)])
     self.k = sp.Matrix([sp.symbols("k_" + str(i)) for i in range(nDimensions)])
     # Function
     self.V_dim = 0.5 * sp.matrix_multiply_elementwise(self.k, (
         (self.position - self.r_shift).applyfunc(lambda x: x ** 2)))  # +self.Voff
     self.V_functional = sp.Sum(self.V_dim[self.i, 0], (self.i, 0, self.nDimensions - 1))
Пример #4
0
def remove_images(expr, var, dt, m1=0, m2=0):

    if m2 == 0 and isinstance(m1, tuple) and len(m1) == 2:
        # Perhaps should warn that this might be deprecated?
        m1, m2 = m1

    remove_all = m1 == 0 and m2 == 0

    const, expr1 = factor_const(expr, var)

    result = sym.S.Zero
    terms = expr1.as_ordered_terms()

    if len(terms) > 1:
        for term in expr1.as_ordered_terms():
            result += remove_images(term, var, dt, m1, m2)
        return const * result

    if not isinstance(expr1, sym.Sum):
        return expr

    sumsym = expr1.args[1].args[0]

    def query(expr):

        return expr.is_Add and expr.has(var) and expr.has(sumsym)

    def value(expr):
        if not expr.is_Add:
            return expr

        if not expr.is_polynomial(var) and not expr.as_poly(var).is_linear:
            return expr
        expr = expr.expand()
        a = expr.coeff(var, 1)
        b = expr.coeff(var, 0)

        if a == 0:
            return expr
        if b / a != -sumsym / dt:
            return expr
        return a * var

    expr1 = expr1.replace(query, value)

    if remove_all:
        return const * expr1.args[0]

    return const * sym.Sum(expr1.args[0], (sumsym, m1, m2))
Пример #5
0
def test_energy_weighted_leastnorm():
    # Test energy model of weighted least norm.
    omega = -5.
    for order in range(0, 3):
        # Test weighted model.
        for weight in np.linspace(0.01, 1., 3):
            n_elec = sp.symbols("n_elec")
            _, dict_energy, _, expr, alpha, beta = make_symbolic_least_norm_model(
                omega, order, weight)
            alpha = sp.Sum(alpha, (n_elec, 2, 13)).doit()
            beta = sp.Sum(beta, (n_elec, 2, 13)).doit()
            weighted = LeastNormGlobalTool(dict_energy,
                                           omega,
                                           order,
                                           weight,
                                           eps=1e-9)

            actual = [weighted.energy(n_elec) for n_elec in range(1, 20)]
            desired = [
                expr[0].subs([("n_elec", n_elec), ('alpha', alpha),
                              ('beta', beta)]).evalf()
                for n_elec in range(1, 20)
            ]
            assert_almost_equal(actual, desired, decimal=4)
Пример #6
0
def generic_function(val, deriv=0):
    """
    Returns specified derivative of a polynomial series. To be used in the place
    of functions for specification of boundary conditions.

    Parameters
    ----------
    val : Sympy symbol
        The variable of the function: x_b should be used.
    deriv : int
        The order of the derivative. Default is zero.
    """
    x_poly = sp.symbols('x_poly')
    polynomial = sp.Sum(a[n] * x_poly**n, (n, 0, n_max))
    return sp.diff(polynomial, x_poly, deriv).subs(x_poly, val)
Пример #7
0
 def parametrization(  # pylint: disable=too-many-arguments
     i: int,
     s: sp.Symbol,
     pole_position: sp.IndexedBase,
     pole_width: sp.IndexedBase,
     residue_constant: sp.IndexedBase,
     beta_constant: sp.IndexedBase,
     n_poles: Union[int, sp.Symbol],
     pole_id: Union[int, sp.Symbol],
 ) -> sp.Expr:
     beta = beta_constant[pole_id]
     gamma = residue_constant[pole_id, i]
     mass = pole_position[pole_id]
     width = pole_width[pole_id, i]
     parametrization = beta * gamma * mass * width / (mass**2 - s)
     return sp.Sum(parametrization, (pole_id, 1, n_poles))
Пример #8
0
 def _initialize_functions(self):
     """
     _initialize_functions
         converts the symbolic mathematics of sympy to a matrix representation that is compatible
         with multi-dimentionality.
     """
     self.position = sp.Matrix([
         sp.symbols("r_" + str(i))
         for i in range(self.constants[self.nDimensions])
     ])
     self.wave_potentials = sp.Matrix([
         sp.symbols("V_" + str(i))
         for i in range(self.constants[self.nWavePotentials])
     ])
     # Function
     self.V_functional = sp.Sum(self.wave_potentials[self.i, 0],
                                (self.i, 0, self.nWavePotentials - 1))
Пример #9
0
    def process_var(self, subscripts, vars_, var):
        subs_ = [subscripts[i] for i in self.subscripts.keys()
                 if f'_{i}' in var]

        if var in self.totals.keys():
            total_subs = [i for i in self.subscripts.keys()
                          if f'_{i}' in var]
            other_subs = [i for i in self.subscripts.keys()
                          if f'_{i}' in var]
            diff = [i for i in total_subs if i
                    not in other_subs]
            for d in diff:
                m = self.subscripts[d]['count']
                var = sp.Sum(var, (d, 1, m))

        var = vars_[var[0]]
        return var
Пример #10
0
def idfs(xk, N:int, r:tuple=()):
    """离散傅里叶级数逆运算

    :Parameters:
        - xk: 离散周期频谱序列,序列只能有1个自变量
        - N: 序列最小数字周期
        - r: 序列一个周期的范围

    :Returns: 原信号序列(离散周期序列),序列自变量为n
    """
    k = tuple(xk.free_symbols)[0]
    n = sy.symbols('n')
    if not r:
        r = (k, 0, N-1)
    W = sy.exp(sy.I * 2 * sy.pi * k * n / N)
    xn = sy.Sum(xk * W, r) / N
    return xn
    def _calculate_z_transform(self):
        z = sympy.symbols('z')
        n = sympy.symbols('n')

        try:
            f = sympy.parsing.sympy_parser.parse_expr(self.line_exp_sample.text())
            F = sympy.Sum(f * z ** (-n), (n, 0, sympy.oo)).doit(noconds=True)

            while isinstance(F, (sympy.Piecewise, sympy.functions.elementary.piecewise.ExprCondPair)):
                F = F.args[0]

        except (ValueError, TypeError, SyntaxError) as ex:
            error_msg = f'ValueError: invalid expression'
            print(ex, error_msg)
            QtWidgets.QMessageBox.about(self, 'Error message', error_msg)
            return -1

        self.label_exp_state_val.setText(str(F))
Пример #12
0
    def parametrization(  # pylint: disable=too-many-arguments
        i: int,
        j: int,
        s: sp.Symbol,
        pole_position: sp.IndexedBase,
        pole_width: sp.IndexedBase,
        residue_constant: sp.IndexedBase,
        n_poles: Union[int, sp.Symbol],
        pole_id: Union[int, sp.Symbol],
    ) -> sp.Expr:
        def residue_function(pole_id: int, i: int) -> sp.Expr:
            return residue_constant[pole_id, i] * sp.sqrt(
                pole_position[pole_id] * pole_width[pole_id, i])

        g_i = residue_function(pole_id, i)
        g_j = residue_function(pole_id, j)
        parametrization = (g_i * g_j) / (pole_position[pole_id]**2 - s)
        return sp.Sum(parametrization, (pole_id, 1, n_poles))
Пример #13
0
def test_piecewise_simplification():
    d2d3_11 = (c * d * TP(x, sp.Piecewise(
        (x, sp.Eq(k, 0)),
        (0, True))) + c * d * TP(sp.Piecewise(
            (x, sp.Eq(k, 0)),
            (0, True)), x) + d * TP(1, sp.Piecewise(
                (x, sp.Eq(k, 0)),
                (0, True))) + d * TP(sp.Piecewise((x, sp.Eq(k, 0)),
                                                  (0, True)), 1))
    assert texpand(d2d3_11) == 0

    expr = sp.Sum(
        sp.Piecewise(
            (c * TP(xy**k,
                    y * xy**(k - q - 1) * y) + TP(y * xy**(k - 1),
                                                  y * xy**(k - q - 1) * y),
             sp.Eq(q, 0)), (0, True)), (q, 0, k - 1))
    assert texpand(expr) == 0
Пример #14
0
def manual_y_computation(weighting_seq, input_signal, T):
    logging.info('ŷ(t) = ĝ(t) * u(t)')

    g_ = sy.IndexedBase('ĝ')
    u = sy.IndexedBase('u')

    y_ = sy.Sum(g_[k] * u[T - k], (k, 0, T))
    logging.info(f'ŷ({T}) = {y_}')

    inter_step = lambda weighting_seq: (y_.doit().subs([
        (u[i], u_value) for i, u_value in enumerate(input_signal)
    ]).subs([(g_[i], g_value) for i, g_value in enumerate(weighting_seq)]))

    g_sym = inter_step(map(lambda x: sy.symbols(str(x)), weighting_seq))
    logging.info(f'ŷ({T}) = {g_sym}')
    g_val = inter_step(weighting_seq)
    logging.info(f'ŷ({T}) = {g_val}')

    return g_val
def state_forced_response_discrete(a, b, u, show_steps=True):
    '''Computes the forced response of the state variables based on the input u.
    x_homo = state_trans_matrix * initial_cond
    
    Params:
        a (list or sympy Matrix): A list of lists for the rows of the A matrix of the system
        b (list or sympy Matrix): A list of lists for the b matrix
        u (list,sympy Matrix, or a constant): the input to the system
        show_steps (bool, True): Pretty prints the steps of the computation
    
    Returns:
        sympy Matrix: the forced response
    '''
    a = sy.Matrix(a)
    b = sy.Matrix(b)
    # T is for tau
    k, i = sy.symbols('k i')
    state_trans_neg = state_transition_matrix_discrete(a,
                                                       k - 1 - i,
                                                       show_steps=False)
    state_trans = state_transition_matrix_discrete(a, k, show_steps=False)
    # This is in case the u param is dependant on k, if it is we need to make it
    # into an i for the summation below
    try:
        u = u.replace(k, i)
    except:
        pass
    unevaluated_conv_sum = sy.Sum(state_trans_neg * b * u, (i, 0, k - 1))
    forced_resp = unevaluated_conv_sum.doit()
    # sympy returns None if the answer is zero
    if not forced_resp:
        forced_resp = sy.zeros(state_trans.shape[0])
    if show_steps:
        print("Finding the forced response")
        display_steps(a, "A matrix")
        display_steps(b, "B matrix")
        display_steps(state_trans, "State transition matrix: ")
        display_steps(state_trans_neg, "Negative state trans matrix")
        display_steps(unevaluated_conv_sum, "The convolution summation")
        display_steps(forced_resp, "Forced response is ")

    return forced_resp
Пример #16
0
    def __init__(self,
                 V_is: t.List[_potential1DCls],
                 s: float = 1.0,
                 Eoff_i: t.List[float] = None,
                 T: float = 298):
        """

        :param V_is:
        :param s:
        :param Eoff_i:
        """

        super().__init__(V_is=V_is, s=s, Eoff_i=Eoff_i)

        #Sympy Implementation
        Eoffis = {"Eoff_" + str(i): Eoff_i[i] for i in range(self.nStates)}
        self.statePotentials = {
            "state_" + str(j): V_is[j]
            for j in range(self.nStates)
        }
        self.states = sp.Matrix([
            sp.symbols(j) - sp.symbols(k)
            for j, k in zip(self.statePotentials, Eoffis)
        ])
        self.constants = {
            **{
                state: value.V
                for state, value in self.statePotentials.items()
            },
            **Eoffis,
            **{
                "s": s,
                self.T: T,
                self.N: self.nStates
            }
        }

        self.V_orig = -1 / (self.beta * self.s_s) * sp.log(
            sp.Sum(sp.exp(-self.beta * self.s_s * (self.states[self.i, 0])),
                   (self.i, 0, self.N - 1)))
        self.V = self.V_orig.subs(self.constants)
        self.dVdpos = sp.diff(self.V, self.position)
Пример #17
0
    def func(self, expr, n, z):

        if not isinstance(expr, AppliedUndef):
            self.error('Expecting function')

        scale, shift = scale_shift(expr.args[0], n)

        # Convert v(n) to V(z), etc.
        name = expr.func.__name__
        func = sym.Function(name[0].upper() + name[1:])

        if not scale.is_constant():
            self.error('Cannot determine if time-expansion or decimation')

        if scale == 1:
            result = func(z)

            if shift != 0:
                result = result * z ** shift
            return result

        if scale.is_integer:
            # Down-sampling produces aliasing
            # Sum(X(z**(1 / M) * exp(-j * 2 * pi * m / M), (m, 0, M - 1)) / M)
            # Down-sampling is not shift invariant so z-transform
            # is an approximation.
            m = self.dummy_var(expr, 'm', level=0, real=True)
            expr = func(z**(1 / scale) *
                        sym.exp(-sym.I * 2 * sym.pi * m / scale))
            return sym.Sum(expr, (m, 0, scale - 1)) / scale

        if not scale.is_rational:
            self.error('Cannot handle arbitrary scaling')

        if scale.p != 1:
            self.error('Cannot handle non-integer time-expansion')

        result = func(z ** scale.q)

        if shift != 0:
            result = result * z ** shift
        return result
Пример #18
0
    def _initialize_functions(self):
        # Parameters
        nDim = self.constants[self.nDim]
        self.position = sp.Matrix(
            [sp.symbols("pos_" + str(i)) for i in range(nDim)])
        self.multiplicity = sp.Matrix(
            [sp.symbols("mult_" + str(i)) for i in range(nDim)])
        self.phase_shift = sp.Matrix(
            [sp.symbols("phase_" + str(i)) for i in range(nDim)])
        self.amplitude = sp.Matrix(
            [sp.symbols("amp_" + str(i)) for i in range(nDim)])
        self.yOffset = sp.Matrix(
            [sp.symbols("yOff_" + str(i)) for i in range(nDim)])

        #Function
        self.V_dim = sp.matrix_multiply_elementwise(
            self.amplitude, (sp.matrix_multiply_elementwise(
                (self.position + self.phase_shift),
                self.multiplicity)).applyfunc(sp.cos)) + self.yOffset
        self.V_orig = sp.Sum(self.V_dim[self.i, 0], (self.i, 0, self.nDim - 1))
Пример #19
0
    def duration(self) -> ExpressionScalar:
        step_size = self._loop_range.step.sympified_expression
        loop_index = sympy.symbols(self._loop_index)
        sum_index = sympy.symbols(self._loop_index)

        # replace loop_index with sum_index dependable expression
        body_duration = self.body.duration.sympified_expression.subs({loop_index: self._loop_range.start.sympified_expression + sum_index*step_size})

        # number of sum contributions
        step_count = sympy.ceiling((self._loop_range.stop.sympified_expression-self._loop_range.start.sympified_expression) / step_size)
        sum_start = 0
        sum_stop = sum_start + (sympy.functions.Max(step_count, 1) - 1)

        # expression used if step_count >= 0
        finite_duration_expression = sympy.Sum(body_duration, (sum_index, sum_start, sum_stop))

        duration_expression = sympy.Piecewise((0, step_count <= 0),
                                              (finite_duration_expression, True))

        return ExpressionScalar(duration_expression)
Пример #20
0
    def match_transform(v):
        if not isinstance(v, sp.Add):
            return None

        terms = v.args
        coeffs_to_terms = split_coefficients_into_dict_keys(terms)

        was_update = False
        new_terms = []

        for (coeff, terms) in coeffs_to_terms.items():
            sums, not_sums = separate_sums(terms)

            for i1 in range(len(sums)):
                for i2 in range(len(sums)):
                    if i1 == i2:
                        continue

                    sum1 = sums[i1]
                    sum2 = sums[i2]

                    func1 = sum1.function
                    func2 = sum2.function

                    var1 = sum1.limits[0][0]
                    var2 = sum2.limits[0][0]

                    if func1.subs(var1, var2 + 1) == func2:
                        # match!
                        was_update = True
                        new_func = func1.subs(var1, var2)
                        new_limits = (var2, sum2.limits[0][1] + 1,
                                      sum2.limits[0][2] + 1)
                        sums[i2] = sp.Sum(new_func, new_limits)

            new_terms.extend([coeff * term for term in not_sums + sums])

        if was_update:
            return sp.Add(*new_terms)
        else:
            return None
Пример #21
0
    def setWeierstrassFunction(self):
        #Example of how to define and set a problem using the parameter class.
        self.p_initialPopulation = 50
        self.p_populationCap = 50
        self.p_specimensPruned = 45
        self.p_mutationRate = 0.001
        self.p_basisFunction = (a * x)
        self.p_targetFitness = 0

        self.p_problemVars = [x1]
        self.p_problemDomain = [(-2, 2)]
        self.p_objectiveFunction = sp.Sum(0.9**n * sp.cos(7**n * np.pi * x1),
                                          (n, self.p_problemDomain[0][0],
                                           self.p_problemDomain[0][1])).doit()
        self.p_constraints = []

        self.p_fitnessSamples = 101
        self.p_maxOrder = 3
        self.p_maxStages = 4
        self.p_fitnessFunc = fixedDomainCorrelationAndMeanSquareFitness
        self.p_reproductionMethod = cellularMethodVariableTermMutation
Пример #22
0
    def _initialize_functions(self):
        # for sympy Sympy Updates - Check!:
        self.statePotentials = {"state_" + str(j): self.V_is[j] for j in range(self.constants[self.nStates])}
        Eoffis = {"Eoff_" + str(i): self.Eoff_i[i] for i in range(self.constants[self.nStates])}
        sis = {"s_" + str(i): self.s_i[i] for i in range(self.constants[self.nStates])}
        lamis = {"lam_" + str(i): self.lam_i[i] for i in range(self.constants[self.nStates])}
        keys = zip(sorted(self.statePotentials.keys()), sorted(Eoffis.keys()), sorted(sis.keys()))

        self.states = sp.Matrix([sp.symbols(l) * (sp.symbols(j) - sp.symbols(k)) for j, k, l in keys])
        self.constants.update(
            {**{state: value.V for state, value in self.statePotentials.items()}, **Eoffis, **sis, **lamis})
        inner_log = sp.Sum(sp.Matrix(list(lamis.keys()))[self.i, 0] * sp.exp(-self.beta * self.states[self.i, 0]),
                           (self.i, 0, self.nStates - 1))
        self.V_functional = -1 / (self.beta * self.sis[0, 0]) * sp.log(inner_log)
        self._update_functions()

        # also make sure that states are up to work:
        [V._update_functions() for V in self.V_is]

        self.ene = self._calculate_energies_singlePos_overwrite
        self.force = self._calculate_dvdpos_singlePos_overwrite
Пример #23
0
 def _initialize_functions(self):
     """
     _initialize_functions
         converts the symbolic mathematics of sympy to a matrix representation that is compatible
         with multi-dimentionality.
     """
     # Parameters
     nDimensions = self.constants[self.nDimensions]
     self.position = sp.Matrix(
         [sp.symbols("r_" + str(i)) for i in range(nDimensions)])
     self.r_shift = sp.Matrix(
         [sp.symbols("r_shift" + str(i)) for i in range(nDimensions)])
     self.V_off = sp.Matrix(
         [sp.symbols("V_off_" + str(i)) for i in range(nDimensions)])
     self.k = sp.Matrix(
         [sp.symbols("k_" + str(i)) for i in range(nDimensions)])
     # Function
     self.V_dim = 0.5 * sp.matrix_multiply_elementwise(
         self.k, ((self.position -
                   self.r_shift).applyfunc(lambda x: x**2)))  # +self.Voff
     self.V_functional = sp.Sum(self.V_dim[self.i, 0],
                                (self.i, 0, self.nDimensions - 1))
Пример #24
0
    def __init__(self, wavePotentials):
        '''
        initializes torsions Potential
        '''
        self.constants = {
            **{
                "wave_" + str(key): wave.V
                for key, wave in enumerate(wavePotentials)
            },
            **{
                self.N: len(wavePotentials) - 1
            }
        }
        self.wavePotentials = sp.Matrix(
            [sp.symbols("wave_" + str(i)) for i in range(len(wavePotentials))])

        self.V_orig = sp.Sum(self.wavePotentials[self.i, 0],
                             (self.i, 0, self.N))
        self.V = self.V_orig.subs(self.constants).subs(self.N,
                                                       len(wavePotentials))

        super().__init__()
Пример #25
0
def handle_sum_or_prod(func, name):
    val = convert_mp(func.mp())
    iter_var = None
    start = None
    if func.subeq():  # e.g. _{i=0}
        iter_var = convert_expr(func.subeq().equality().expr(0))
        start = convert_expr(func.subeq().equality().expr(1))
    elif func.subexpr().expr():  # _{expr}
        iter_var = convert_expr(func.subexpr().expr())
    else:  # _atom
        iter_var = convert_atom(func.subexpr().atom())
    if func.supexpr():
        if func.supexpr().expr():  # ^{expr}
            end = convert_expr(func.supexpr().expr())
        else:  # ^atom
            end = convert_atom(func.supexpr().atom())
    if name == "summation":
        if start is not None:
            return sympy.Sum(val, (iter_var, start, end))
        else:
            return sympy.Function('sum_{' + str(iter_var) + '}')(val)
    elif name == "product":
        return sympy.Product(val, (iter_var, start, end))
Пример #26
0
        def calculator(pool, var_node):
            """
            Symbolically sums the expression of the node.
            :return: a lambda expression that substitutes the given lower- and upper bound in the sum
            """
            variable, node_id = var_node
            expression = pool.get_node(node_id).expression
            variables = {str(v): v for v in expression.free_symbols}

            if len(variables) == 0:
                return lambda lb, ub: (ub - lb + 1) * float(expression)

            v = variables[variable] if variable in variables else sympy.S(variable)
            # TODO add caching again
            try:
                # expression = sympy.expand(expression)
                # print("Value at r=10 is {}".format(expression.subs({"r": 10})))
                result = sympy.Sum(expression, (v, self.lb, self.ub)).doit()
                # print("Symbolic sum of {} = {}".format(expression, result))
                return lambda lb, ub: result.subs({self.lb: lb, self.ub: ub})
            except sympy.BasePolynomialError as e:
                print("Problem trying to sum the expression {} for variable {}"
                      .format(expression, v))
                raise e
Пример #27
0
    def integral(self) -> Dict[ChannelID, ExpressionScalar]:

        step_size = self._loop_range.step.sympified_expression
        loop_index = sympy.symbols(self._loop_index)
        sum_index = sympy.symbols(self._loop_index)

        body_integrals = self.body.integral
        body_integrals = {
            c: body_integrals[c].sympified_expression.subs(
                {loop_index: self._loop_range.start.sympified_expression + sum_index*step_size}
            )
            for c in body_integrals
        }

        # number of sum contributions
        step_count = sympy.ceiling((self._loop_range.stop.sympified_expression-self._loop_range.start.sympified_expression) / step_size)
        sum_start = 0
        sum_stop = sum_start + (sympy.functions.Max(step_count, 1) - 1)

        for c in body_integrals:
            channel_integral_expr = sympy.Sum(body_integrals[c], (sum_index, sum_start, sum_stop))
            body_integrals[c] = ExpressionScalar(channel_integral_expr)

        return body_integrals
Пример #28
0
def test_sum():

    sum = sympy.Sum(k, (k, 1, 100))
    expanded_sum = sum.doit()

    print(sum)
    print(expanded_sum)

    x = pystencils.fields('x: float32[1d]')

    assignments = pystencils.AssignmentCollection({x.center(): sum})

    ast = pystencils.create_kernel(assignments)
    code = str(pystencils.show_code(ast))
    kernel = ast.compile()

    print(code)
    assert 'double sum' in code

    array = np.zeros((10, ), np.float32)

    kernel(x=array)

    assert np.allclose(array, int(expanded_sum) * np.ones_like(array))
Пример #29
0
class envelopedPotential(_potentialNDCls):
    """
    This implementation of exponential Coupling for EDS is a more numeric robust and variable implementation, it allows N states.
    Therefore the computation of energies and the deviation is not symbolic.

    Here N-states are coupled by the log-sum-exp resulting in a new reference state $V_R$,

    $V_R = -1/{\beta} * \ln(\sum_i^Ne^(-\beta*s*(V_i-E^R_i)))$

    This potential coupling is for example used in EDS.
    """
    name = "Enveloping Potential"

    T, kb, position = sp.symbols("T kb r")
    beta = 1 / (kb * T)

    Vis = sp.Matrix(["V_i"])
    Eoffis = sp.Matrix(["Eoff_i"])
    sis = sp.Matrix(["s_i"])
    i, nStates = sp.symbols("i N")
    V_functional = -1 / (beta * sis[0, 0]) * sp.log(
        sp.Sum(sp.exp(-beta * sis[i, 0] * (Vis[i, 0] - Eoffis[i, 0])), (i, 0, nStates)))

    def __init__(self, V_is: t.List[_potentialNDCls] = (
            harmonicOscillatorPotential(nDimensions=2), harmonicOscillatorPotential(r_shift=[3,3], nDimensions=2)),
                 s: float = 1.0, eoff: t.List[float] = None, T: float = 1, kb: float = 1):
        """
            __init__
                This function constructs a enveloped potential, enveloping all given states.

        Parameters
        ----------
        V_is: List[_potential1DCls], optional
            The states(potential classes) to be enveloped (default: [harmonicOscillatorPotential(), harmonicOscillatorPotential(x_shift=3)])

        s: float, optional
            the smoothing parameter, lowering the barriers between the states
        eoff: List[float], optional
            the energy offsets of the individual states in the reference potential. These can be used to allow a more uniform sampling. (default: seta ll to 0)
        T: float, optional
            the temperature of the reference state (default: 1 = T)
        kb: float, optional
            the boltzman constant (default: 1 = kb)

        """
        self.constants = {self.T: T, self.kb: kb}
        nStates = len(V_is)
        self._Eoff_i = [0 for x in range(nStates)]
        self._s = [0 for x in range(nStates)]
        self._V_is = [0 for x in range(nStates)]

        # for calculate implementations
        self.V_is = V_is
        self.s_i = s
        self.Eoff_i = eoff

        super().__init__(nDimensions=V_is[0].constants[V_is[0].nDimensions], nStates=len(V_is))

    def _initialize_functions(self):
        """
        build the symbolic functionality.
        """
        # for sympy Sympy Updates - Check!:
        self.statePotentials = {"state_" + str(j): self.V_is[j] for j in range(self.constants[self.nStates])}
        Eoffis = {"Eoff_" + str(i): self.Eoff_i[i] for i in range(self.constants[self.nStates])}
        sis = {"s_" + str(i): self.s_i[i] for i in range(self.constants[self.nStates])}
        keys = zip(sorted(self.statePotentials.keys()), sorted(Eoffis.keys()), sorted(sis.keys()))

        self.states = sp.Matrix([sp.symbols(l) * (sp.symbols(j) - sp.symbols(k)) for j, k, l in keys])
        self.constants.update({**{state: value.V for state, value in self.statePotentials.items()}, **Eoffis, **sis})

        self.V_functional = -1 / (self.beta * self.sis[0, 0]) * sp.log(
            sp.Sum(sp.exp(-self.beta * self.states[self.i, 0]), (self.i, 0, self.nStates - 1)))
        self._update_functions()

        # also make sure that states are up to work:
        [V._update_functions() for V in self.V_is]

        if (all([self.s_i[0] == s for s in self.s_i[1:]])):
            self.ene = self._calculate_energies_singlePos_overwrite_oneS
        else:
            self.ene = self._calculate_energies_singlePos_overwrite_multiS
        self.force = self._calculate_dvdpos_singlePos_overwrite

    @property
    def V_is(self) -> t.List[_potentialNDCls]:
        """
        V_is are the state potential classes enveloped by the reference state.

        Returns
        -------
        V_is: t.List[_potential1DCls]
        """
        return self._V_is

    @V_is.setter
    def V_is(self, V_is: t.List[_potentialNDCls]):
        if (isinstance(V_is, Iterable) and all([isinstance(Vi, _potentialNDCls) for Vi in V_is])):
            self._V_is = V_is
            self.constants.update({self.nStates: len(V_is)})
        else:
            raise IOError("Please give the enveloped potential for V_is only 1D-Potential classes in a list.")

    def set_Eoff(self, Eoff: Union[Number, Iterable[Number]]):
        """
        This function is setting the Energy offsets of the states enveloped by the reference state.
        Parameters
        ----------
        Eoff: Union[Number, Iterable[Number]]
        """
        self.Eoff_i = Eoff

    @property
    def Eoff(self) -> t.List[Number]:
        """
        The Energy offsets are used to bias the single states in the reference potential by a constant offset.
        Therefore each state of the enveloping potential has its own energy offset.

        Returns
        -------
        Eoff:t.List[Number]

        """
        return self.Eoff_i

    @Eoff.setter
    def Eoff(self, Eoff: Union[Number, Iterable[Number], None]):
        self.Eoff_i = Eoff

    @property
    def Eoff_i(self) -> t.List[Number]:
        """
        The Energy offsets are used to bias the single states in the reference potential by a constant offset.
        Therefore each state of the enveloping potential has its own energy offset.

        Returns
        -------
        Eoff:t.List[Number]

        """
        return self._Eoff_i

    @Eoff_i.setter
    def Eoff_i(self, Eoff: Union[Number, Iterable[Number], None]):
        if (isinstance(Eoff, type(None))):
            self._Eoff_i = [0.0 for state in range(self.constants[self.nStates])]
            Eoffis = {"Eoff_" + str(i): self.Eoff_i[i] for i in range(self.constants[self.nStates])}
            self.constants.update({**Eoffis})
        elif (len(Eoff) == self.constants[self.nStates]):
            self._Eoff_i = Eoff
            Eoffis = {"Eoff_" + str(i): self.Eoff_i[i] for i in range(self.constants[self.nStates])}
            self.constants.update({**Eoffis})
        else:
            raise IOError(
                "Energy offset Vector and state potentials don't have the same length!\n states in Eoff " + str(
                    len(Eoff)) + "\t states in Vi" + str(len(self.V_is)))

    def set_s(self, s: Union[Number, Iterable[Number]]):
        """
            set_s
            is a function used to set an smoothing parameter.
        Parameters
        ----------
        s:Union[Number, Iterable[Number]]

        Returns
        -------

        """
        self.s_i = s

    @property
    def s(self) -> t.List[Number]:
        return self.s_i

    @s.setter
    def s(self, s: Union[Number, Iterable[Number]]):
        self.s_i = s

    @property
    def s_i(self) -> t.List[Number]:
        return self._s

    @s_i.setter
    def s_i(self, s: Union[Number, Iterable[Number]]):
        if (isinstance(s, Number)):
            self._s = [s for x in range(self.constants[self.nStates])]
            sis = {"s_" + str(i): self.s_i[i] for i in range(self.constants[self.nStates])}
            self.constants.update({**sis})
        elif (len(s) == self.constants[self.nStates]):
            self._s = s
            sis = {"s_" + str(i): self.s_i[i] for i in range(self.constants[self.nStates])}
            self.constants.update({**sis})
        else:
            raise IOError("s Vector/Number and state potentials don't have the same length!\n states in s " + str(
                len(s)) + "\t states in Vi" + str(len(self.V_is)))
        self._update_functions()

    def _calculate_energies_singlePos_overwrite_multiS(self, positions) -> np.array:
        sum_prefactors, _ = self._logsumexp_calc_gromos(positions)
        beta = self.constants[self.T] * self.constants[self.kb]  # kT - *self.constants[self.T]
        Vr = (-1 / (beta)) * sum_prefactors
        return np.squeeze(Vr)

    def _calculate_energies_singlePos_overwrite_oneS(self, positions) -> np.array:
        sum_prefactors, _ = self._logsumexp_calc(positions)
        beta = self.constants[self.T] * self.constants[self.kb]
        Vr = (-1 / (beta * self.s_i[0])) * sum_prefactors
        return np.squeeze(Vr)

    def _calculate_dvdpos_singlePos_overwrite(self, positions: (t.Iterable[float])) -> np.array:
        """
        Parameters
        ----------
        positions

        Returns
        -------

        """
        positions = np.array(positions, ndmin=2)
        # print("Pos: ", position)

        V_R_part, V_Is_ene = self._logsumexp_calc_gromos(positions)
        V_R_part = np.array(V_R_part, ndmin=2).T
        # print("V_R_part: ", V_R_part.shape, V_R_part)
        # print("V_I_ene: ",V_Is_ene.shape, V_Is_ene)
        V_Is_dhdpos = np.array([-statePot.force(positions) for statePot in self.V_is], ndmin=1).T
        # print("V_I_force: ",V_Is_dhdpos.shape, V_Is_dhdpos)

        adapt = np.concatenate([V_R_part for s in range(self.constants[self.nStates])], axis=1)
        # print("ADAPT: ",adapt.shape, adapt)
        scaling = np.exp(V_Is_ene - adapt)
        # print("scaling: ", scaling.shape, scaling)
        dVdpos_state = np.multiply(scaling,
                                   V_Is_dhdpos)  # np.array([(ene/V_R_part) * force for ene, force in zip(V_Is_ene, V_Is_dhdpos)])
        # print("state_contributions: ",dVdpos_state.shape, dVdpos_state)
        dVdpos = np.sum(dVdpos_state, axis=1)
        # print("forces: ",dVdpos.shape, dVdpos)

        return np.squeeze(dVdpos)

    def _logsumexp_calc(self, position):
        prefactors = []
        beta = self.constants[self.T] * self.constants[self.kb]
        for state in range(self.constants[self.nStates]):
            prefactor = np.array(-beta * self.s_i[state] * (self.V_is[state].ene(position) - self.Eoff_i[state]),
                                 ndmin=1).T
            prefactors.append(prefactor)
        prefactors = np.array(prefactors, ndmin=2).T

        from scipy.special import logsumexp
        # print("Prefactors", prefactors)
        sum_prefactors = logsumexp(prefactors, axis=1)
        # print("logexpsum: ", np.squeeze(sum_prefactors))

        return np.squeeze(sum_prefactors), np.array(prefactors, ndmin=2).T

    def _logsumexp_calc_gromos(self, position):
        """
        code from gromos:

        Parameters
        ----------
        position

        Returns
        -------

        """
        prefactors = []
        beta = self.constants[self.T] * self.constants[self.kb]  # kT - *self.constants[self.T]
        partA = np.array(-beta * self.s_i[0] * (self.V_is[0].ene(position) - self.Eoff_i[0]), ndmin=1)
        partB = np.array(-beta * self.s_i[1] * (self.V_is[1].ene(position) - self.Eoff_i[1]), ndmin=1)

        partAB = np.array([partA, partB]).T
        log_prefac = 1 + np.exp(np.min(partAB, axis=1) - np.max(partAB, axis=1))
        sum_prefactors = np.max(partAB, axis=1) + np.log(log_prefac)

        prefactors.append(partA)
        prefactors.append(partB)

        # more than two states!
        for state in range(2, self.constants[self.nStates]):
            partN = np.array(-beta * self.s_i[state] * (self.V_is[state].ene(position) - self.Eoff_i[state]), ndmin=1)
            prefactors.append(partN)
            sum_prefactors = np.max([sum_prefactors, partN], axis=1) + np.log(1 + np.exp(
                np.min([sum_prefactors, partN], axis=1) - np.max([sum_prefactors, partN], axis=1)))
            # print("prefactors: ", sum_prefactors)
        return sum_prefactors, np.array(prefactors, ndmin=2).T
Пример #30
0
class sumPotentials(_potentialNDCls):
    """
    Adds n different potentials.
     For adding up wavepotentials, we recommend using the addedwavePotential class.
    """
    name: str = "Summed Potential"

    position = sp.symbols("r")
    potentials: sp.Matrix = sp.Matrix([sp.symbols("V_x")])

    nPotentials = sp.symbols("N")
    i = sp.symbols("i", cls=sp.Idx)

    V_functional = sp.Sum(potentials[i, 0], (i, 0, nPotentials))

    def __init__(self, potentials: t.List[_potentialNDCls] = (harmonicOscillatorPotential(), harmonicOscillatorPotential(r_shift=[1,1,1], nDimensions=3))):
        """
        __init__
            This is the Constructor of an summed Potentials

        Parameters
        ----------
        potentials: List[_potential2DCls], optional
            it uses the 2D potential class to generate its potential,
            default to (wavePotential(), wavePotential(multiplicity=[3, 3]))
        """
        if(all([potentials[0].constants[V.nDimensions] == V.constants[V.nDimensions] for V in potentials])):
            nDim = potentials[0].constants[potentials[0].nDimensions]
        else:
            raise ValueError("The potentials don't share the same dimensionality!\n\t"+str([V.constants[V.nDimensions] for V in potentials]))


        self.constants = {self.nPotentials: len(potentials)}
        self.constants.update({"V_" + str(i): potentials[i].V for i in range(len(potentials))})

        super().__init__(nDimensions=nDim)

    def _initialize_functions(self):
        """
        _initialize_functions
            converts the symbolic mathematics of sympy to a matrix representation that is compatible
            with multi-dimentionality.
        """
        self.position = sp.Matrix([sp.symbols("r_" + str(i)) for i in range(self.constants[self.nDimensions])])
        self.potentials = sp.Matrix(
            [sp.symbols("V_" + str(i)) for i in range(self.constants[self.nPotentials])])
        # Function
        self.V_functional = sp.Sum(self.potentials[self.i, 0], (self.i, 0, self.nPotentials - 1))

    def __str__(self) -> str:
        msg = self.__name__() + "\n"
        msg += "\tStates: " + str(self.constants[self.nStates]) + "\n"
        msg += "\tDimensions: " + str(self.nDimensions) + "\n"
        msg += "\n\tFunctional:\n "
        msg += "\t\tV:\t" + str(self.V_functional) + "\n"
        msg += "\t\tdVdpos:\t" + str(self.dVdpos_functional) + "\n"
        msg += "\n\tSimplified Function\n"
        msg += "\t\tV:\t" + str(self.V) + "\n"
        msg += "\t\tdVdpos:\t" + str(self.dVdpos) + "\n"
        msg += "\n"
        return msg

    # OVERRIDE
    def _update_functions(self):
        """
        _update_functions
            calculates the current energy and derivative of the energy
        """
        super()._update_functions()

        self.tmp_Vfunc = self._calculate_energies
        self.tmp_dVdpfunc = self._calculate_dVdpos