Пример #1
0
def test_products():
    assert TensorProduct(R2.dx, R2.dy)(
        R2.e_x, R2.e_y) == R2.dx(R2.e_x) * R2.dy(R2.e_y) == 1
    assert TensorProduct(R2.dx, R2.dy)(None, R2.e_y) == R2.dx
    assert TensorProduct(R2.dx, R2.dy)(R2.e_x, None) == R2.dy
    assert TensorProduct(R2.dx, R2.dy)(R2.e_x) == R2.dy
    assert TensorProduct(R2.x, R2.dx) == R2.x * R2.dx
    assert TensorProduct(R2.e_x, R2.e_y)(
        R2.x, R2.y) == R2.e_x(R2.x) * R2.e_y(R2.y) == 1
    assert TensorProduct(R2.e_x, R2.e_y)(None, R2.y) == R2.e_x
    assert TensorProduct(R2.e_x, R2.e_y)(R2.x, None) == R2.e_y
    assert TensorProduct(R2.e_x, R2.e_y)(R2.x) == R2.e_y
    assert TensorProduct(R2.x, R2.e_x) == R2.x * R2.e_x
    assert TensorProduct(R2.dx, R2.e_y)(
        R2.e_x, R2.y) == R2.dx(R2.e_x) * R2.e_y(R2.y) == 1
    assert TensorProduct(R2.dx, R2.e_y)(None, R2.y) == R2.dx
    assert TensorProduct(R2.dx, R2.e_y)(R2.e_x, None) == R2.e_y
    assert TensorProduct(R2.dx, R2.e_y)(R2.e_x) == R2.e_y
    assert TensorProduct(R2.x, R2.e_x) == R2.x * R2.e_x
    assert TensorProduct(R2.e_x, R2.dy)(
        R2.x, R2.e_y) == R2.e_x(R2.x) * R2.dy(R2.e_y) == 1
    assert TensorProduct(R2.e_x, R2.dy)(None, R2.e_y) == R2.e_x
    assert TensorProduct(R2.e_x, R2.dy)(R2.x, None) == R2.dy
    assert TensorProduct(R2.e_x, R2.dy)(R2.x) == R2.dy
    assert TensorProduct(R2.e_y, R2.e_x)(R2.x**2 + R2.y**2,
                                         R2.x**2 + R2.y**2) == 4 * R2.x * R2.y

    assert WedgeProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y) == 1
    assert WedgeProduct(R2.e_x, R2.e_y)(R2.x, R2.y) == 1
def test_functional_diffgeom_ch6():
    u0, u1, u2, v0, v1, v2, w0, w1, w2 = symbols('u0:3, v0:3, w0:3', real=True)

    u = u0*R2.e_x + u1*R2.e_y
    v = v0*R2.e_x + v1*R2.e_y
    wp = WedgeProduct(R2.dx, R2.dy)
    assert wp(u, v) == u0*v1 - u1*v0

    u = u0*R3_r.e_x + u1*R3_r.e_y + u2*R3_r.e_z
    v = v0*R3_r.e_x + v1*R3_r.e_y + v2*R3_r.e_z
    w = w0*R3_r.e_x + w1*R3_r.e_y + w2*R3_r.e_z
    wp = WedgeProduct(R3_r.dx, R3_r.dy, R3_r.dz)
    assert wp(
        u, v, w) == Matrix(3, 3, [u0, u1, u2, v0, v1, v2, w0, w1, w2]).det()

    a, b, c = symbols('a, b, c', cls=Function)
    a_f = a(R3_r.x, R3_r.y, R3_r.z)
    b_f = b(R3_r.x, R3_r.y, R3_r.z)
    c_f = c(R3_r.x, R3_r.y, R3_r.z)
    theta = a_f*R3_r.dx + b_f*R3_r.dy + c_f*R3_r.dz
    dtheta = Differential(theta)
    da = Differential(a_f)
    db = Differential(b_f)
    dc = Differential(c_f)
    expr = dtheta - WedgeProduct(
        da, R3_r.dx) - WedgeProduct(db, R3_r.dy) - WedgeProduct(dc, R3_r.dz)
    assert expr.rcall(R3_r.e_x, R3_r.e_y) == 0
Пример #3
0
def test_products():
    assert TensorProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y) == R2.dx(R2.e_x)*R2.dy(R2.e_y) == 1
    assert WedgeProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y) == 1
    assert TensorProduct(R2.dx, R2.dy)(None, R2.e_y) == R2.dx
    assert TensorProduct(R2.dx, R2.dy)(R2.e_x, None) == R2.dy
    assert TensorProduct(R2.dx, R2.dy)(R2.e_x) == R2.dy
    assert TensorProduct(R2.x, R2.dx) == R2.x*R2.dx
Пример #4
0
def test_helpers_and_coordinate_dependent():
    one_form = R2.dr + R2.dx
    two_form = Differential(R2.x * R2.dr + R2.r * R2.dx)
    three_form = Differential(R2.y * two_form) + Differential(
        R2.x * Differential(R2.r * R2.dr))
    metric = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dy, R2.dy)
    metric_ambig = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dr, R2.dr)
    misform_a = TensorProduct(R2.dr, R2.dr) + R2.dr
    misform_b = R2.dr**4
    misform_c = R2.dx * R2.dy
    twoform_not_sym = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dx, R2.dy)
    twoform_not_TP = WedgeProduct(R2.dx, R2.dy)

    one_vector = R2.e_x + R2.e_y
    two_vector = TensorProduct(R2.e_x, R2.e_y)
    three_vector = TensorProduct(R2.e_x, R2.e_y, R2.e_x)
    two_wp = WedgeProduct(R2.e_x, R2.e_y)

    assert covariant_order(one_form) == 1
    assert covariant_order(two_form) == 2
    assert covariant_order(three_form) == 3
    assert covariant_order(two_form + metric) == 2
    assert covariant_order(two_form + metric_ambig) == 2
    assert covariant_order(two_form + twoform_not_sym) == 2
    assert covariant_order(two_form + twoform_not_TP) == 2

    assert contravariant_order(one_vector) == 1
    assert contravariant_order(two_vector) == 2
    assert contravariant_order(three_vector) == 3
    assert contravariant_order(two_vector + two_wp) == 2

    raises(ValueError, lambda: covariant_order(misform_a))
    raises(ValueError, lambda: covariant_order(misform_b))
    raises(ValueError, lambda: covariant_order(misform_c))

    assert twoform_to_matrix(metric) == Matrix([[1, 0], [0, 1]])
    assert twoform_to_matrix(twoform_not_sym) == Matrix([[1, 0], [1, 0]])
    assert twoform_to_matrix(twoform_not_TP) == Matrix([[0, -1], [1, 0]])

    raises(ValueError, lambda: twoform_to_matrix(one_form))
    raises(ValueError, lambda: twoform_to_matrix(three_form))
    raises(ValueError, lambda: twoform_to_matrix(metric_ambig))

    raises(ValueError, lambda: metric_to_Christoffel_1st(twoform_not_sym))
    raises(ValueError, lambda: metric_to_Christoffel_2nd(twoform_not_sym))
    raises(ValueError, lambda: metric_to_Riemann_components(twoform_not_sym))
    raises(ValueError, lambda: metric_to_Ricci_components(twoform_not_sym))
Пример #5
0
def ocp_to_bvp(ocp):
    ws = init_workspace(ocp)
    problem_name = ws['problem_name']
    independent_variable = ws['independent_var']
    independent_variable_units = ws['independent_var_units']
    states = ws['states']
    states_rates = ws['states_rates']
    states_units = ws['states_units']
    controls = ws['controls']
    controls_units = ws['controls_units']
    constants = ws['constants']
    constants_units = ws['constants_units']
    constants_values = ws['constants_values']
    constants_of_motion = ws['constants_of_motion']
    constants_of_motion_values = ws['constants_of_motion_values']
    constants_of_motion_units = ws['constants_of_motion_units']
    symmetries = ws['symmetries']
    constraints = ws['constraints']
    constraints_units = ws['constraints_units']
    quantities = ws['quantities']
    quantities_values = ws['quantities_values']
    parameters = ws['parameters']
    parameters_units = ws['parameters_units']
    initial_cost = ws['initial_cost']
    initial_cost_units = ws['initial_cost_units']
    terminal_cost = ws['terminal_cost']
    terminal_cost_units = ws['terminal_cost_units']
    path_cost = ws['path_cost']
    path_cost_units = ws['path_cost_units']

    if initial_cost != 0:
        cost_units = initial_cost_units
    elif terminal_cost != 0:
        cost_units = terminal_cost_units
    elif path_cost != 0:
        cost_units = path_cost_units * independent_variable_units
    else:
        raise ValueError(
            'Initial, path, and terminal cost functions are not defined.')

    dynamical_parameters = []

    quantity_vars, quantity_list, derivative_fn = process_quantities(
        quantities, quantities_values)
    for var in quantity_vars.keys():
        for ii in range(len(states_rates)):
            states_rates[ii] = states_rates[ii].subs(Symbol(var),
                                                     quantity_vars[var])

    Q = Manifold(states, 'State_Space')
    E = Manifold(states + controls, 'Input_Space')
    R = Manifold([independent_variable], 'Independent_Space')
    tau_Q = FiberBundle(Q, R, 'State_Bundle')
    tau_E = FiberBundle(E, R, 'Input_Bundle')
    J1tau_Q = JetBundle(tau_Q, 1, 'Jet_Bundle')
    num_states = len(states)
    num_states_total = len(J1tau_Q.vertical.base_coords)

    hamiltonian, hamiltonian_units, costates, costates_units = make_hamiltonian(
        states, states_rates, states_units, path_cost, cost_units)
    setx = dict(zip(states + costates, J1tau_Q.vertical.base_coords))
    vector_names = [Symbol('D_' + str(x)) for x in states]
    settangent = dict(
        zip(vector_names, J1tau_Q.vertical.base_vectors[:num_states]))

    # Change original terms to be written on manifolds so the diffy g calculations are handled properly
    states = [x.subs(setx, simultaneous=True) for x in states]
    states_rates = [x.subs(setx, simultaneous=True) for x in states_rates]
    costates = J1tau_Q.vertical.base_coords[num_states:]
    constants_of_motion_values = [
        x.subs(setx, simultaneous=True) for x in constants_of_motion_values
    ]
    symmetries = [x.subs(setx, simultaneous=True) for x in symmetries]
    symmetries = [x.subs(settangent, simultaneous=True) for x in symmetries]
    constraints['initial'] = [
        x.subs(setx, simultaneous=True) for x in constraints['initial']
    ]
    constraints['terminal'] = [
        x.subs(setx, simultaneous=True) for x in constraints['terminal']
    ]
    initial_cost = initial_cost.subs(setx, simultaneous=True)
    terminal_cost = terminal_cost.subs(setx, simultaneous=True)

    hamiltonian = hamiltonian.subs(setx, simultaneous=True)

    coparameters = make_costate_names(parameters)
    coparameters_units = [
        path_cost_units / parameter_units
        for parameter_units in parameters_units
    ]
    coparameters_rates = make_costate_rates(hamiltonian, parameters,
                                            coparameters, derivative_fn)

    quads = []
    quads_rates = []
    quads_units = []
    quads += coparameters
    quads_rates += coparameters_rates
    quads_units += coparameters_units

    pi = 0
    omega = 0
    for ii in range(num_states):
        pi += WedgeProduct(J1tau_Q.base_vectors[ii],
                           J1tau_Q.base_vectors[ii + num_states])
        omega += WedgeProduct(J1tau_Q.base_oneforms[ii],
                              J1tau_Q.base_oneforms[ii + num_states])

    state_costate_pairing = 0
    for ii in range(num_states):
        state_costate_pairing += TensorProduct(
            J1tau_Q.base_coords[ii + num_states] *
            J1tau_Q.base_vectors[ii]) + TensorProduct(
                J1tau_Q.base_coords[ii] *
                J1tau_Q.base_vectors[ii + num_states])

    constant_2_value = {
        c: v
        for c, v in zip(constants_of_motion, constants_of_motion_values)
    }
    constant_2_units = {
        c: u
        for c, u in zip(constants_of_motion, constants_of_motion_units)
    }

    reduced_states = states + costates
    original_states = copy.copy(reduced_states)
    reduced_states_units = states_units + costates_units
    state_2_units = {
        x: u
        for x, u in zip(reduced_states, reduced_states_units)
    }

    X_H = pi.rcall(None, hamiltonian)
    equations_of_motion = [X_H.rcall(x) for x in J1tau_Q.vertical.base_coords]

    augmented_initial_cost, augmented_initial_cost_units, initial_lm_params, initial_lm_params_units = make_augmented_cost(
        initial_cost,
        cost_units,
        constraints,
        constraints_units,
        location='initial')
    augmented_terminal_cost, augmented_terminal_cost_units, terminal_lm_params, terminal_lm_params_units = make_augmented_cost(
        terminal_cost,
        cost_units,
        constraints,
        constraints_units,
        location='terminal')

    dV_cost_initial = J1tau_Q.verticalexteriorderivative(
        augmented_initial_cost)
    dV_cost_terminal = J1tau_Q.verticalexteriorderivative(
        augmented_terminal_cost)
    bc_initial = constraints['initial'] + [
        costate + dV_cost_initial.rcall(D_x) for costate, D_x in zip(
            costates, J1tau_Q.vertical.base_vectors[:num_states])
    ] + [
        coparameter - derivative_fn(augmented_initial_cost, parameter)
        for parameter, coparameter in zip(parameters, coparameters)
    ]
    bc_terminal = constraints['terminal'] + [
        costate - dV_cost_terminal.rcall(D_x) for costate, D_x in zip(
            costates, J1tau_Q.vertical.base_vectors[:num_states])
    ] + [
        coparameter - derivative_fn(augmented_terminal_cost, parameter)
        for parameter, coparameter in zip(parameters, coparameters)
    ]
    bc_terminal = make_time_bc(constraints, hamiltonian, bc_terminal)
    dHdu = make_dhdu(hamiltonian, controls, derivative_fn)
    control_law = make_control_law(dHdu, controls)

    tf_var = sympify('tf')
    dynamical_parameters = [tf_var] + parameters
    dynamical_parameters_units = [independent_variable_units
                                  ] + parameters_units
    nondynamical_parameters = initial_lm_params + terminal_lm_params
    nondynamical_parameters_units = initial_lm_params_units + terminal_lm_params_units

    subalgebras = []
    if len(constants_of_motion) > 0:
        logging.info('Checking commutation relations... ')
        num_consts = len(constants_of_motion)

        commutation_relations = [[None for ii in range(num_consts)]
                                 for jj in range(num_consts)]
        for ii, c1 in enumerate(constants_of_motion_values):
            for jj, c2 in enumerate(constants_of_motion_values):
                commutation_relations[ii][jj] = pi.rcall(c1, c2)

        for ii, c1 in enumerate(constants_of_motion_values):
            subalgebras.append({constants_of_motion[ii]})
            for jj in range(0, num_consts):
                if commutation_relations[ii][jj] != 0:
                    subalgebras[-1] |= {constants_of_motion[jj]}

        subalgebras = [
            gs for ii, gs in enumerate(subalgebras)
            if gs not in subalgebras[ii + 1:]
        ]
        reducible_subalgebras = [len(gs) == 1 for gs in subalgebras]
        logging.info('Done. ' + str(sum(reducible_subalgebras)) + ' of ' +
                     str(len(subalgebras)) +
                     ' subalgebras are double reducible.')

    for subalgebra in subalgebras:
        free_vars = set()
        dim = len(subalgebra)
        if dim > 1:
            raise NotImplementedError

        for c in subalgebra:
            free_vars |= constant_2_value[c].atoms(reduced_states[0])

        logging.info('Attempting reduction of ' + str(subalgebra) + '...')

        eq_set = [c - constant_2_value[c] for ii, c in enumerate(subalgebra)]

        constants_sol = sympy.solve(eq_set,
                                    list(free_vars),
                                    dict=False,
                                    minimal=True,
                                    simplify=False)
        for x in constants_sol:
            reduced_states.remove(x)
            quads.append(state_costate_pairing.rcall(x))
            quant = [constant_2_value[c] for c in subalgebra][0]
            quads_rates.append(J1tau_Q.flat(X_H).rcall(pi.rcall(None, quant)))
            quads_units.append(state_2_units[state_costate_pairing.rcall(x)])
            reduced_states.remove(state_costate_pairing.rcall(x))

        temp = copy.copy(subalgebra)
        temp2 = copy.copy(temp)
        dynamical_parameters.append(temp.pop())
        dynamical_parameters_units.append(constant_2_units[temp2.pop()])

        hamiltonian = hamiltonian.subs(constants_sol, simultaneous=True)
        pi = pi.subs(constants_sol, simultaneous=True
                     )  # TODO: Also change the vectors and differential forms
        X_H = pi.rcall(None, hamiltonian)
        equations_of_motion = [X_H.rcall(x) for x in reduced_states]

        for ii in range(len(quads_rates)):
            quads_rates[ii] = quads_rates[ii].subs(constants_sol,
                                                   simultaneous=True)

        for ii in range(len(control_law)):
            for control in control_law[ii]:
                control_law[ii][control] = control_law[ii][control].subs(
                    constants_sol, simultaneous=True)

        for ii in range(len(bc_initial)):
            bc_initial[ii] = bc_initial[ii].subs(constants_sol,
                                                 simultaneous=True)

        for ii in range(len(bc_terminal)):
            bc_terminal[ii] = bc_terminal[ii].subs(constants_sol,
                                                   simultaneous=True)

        logging.info('Done.')

    # Generate the problem data
    control_law = [{str(u): str(law[u])
                    for u in law.keys()} for law in control_law]
    out = {
        'method':
        'diffyg',
        'problem_name':
        problem_name,
        'aux_list': [{
            'type': 'const',
            'vars': [str(k) for k in constants]
        }],
        'states': [str(x) for x in reduced_states],
        'states_units': [str(state_2_units[x]) for x in reduced_states],
        'deriv_list': [str(tf_var * rate) for rate in equations_of_motion],
        'quads': [str(x) for x in quads],
        'quads_rates': [str(tf_var * x) for x in quads_rates],
        'quads_units': [str(x) for x in quads_units],
        'constants': [str(c) for c in constants],
        'constants_units': [str(c) for c in constants_units],
        'constants_values': [float(c) for c in constants_values],
        'constants_of_motion': [str(c) for c in constants_of_motion],
        'dynamical_parameters': [str(c) for c in dynamical_parameters],
        'dynamical_parameters_units':
        [str(c) for c in dynamical_parameters_units],
        'nondynamical_parameters': [str(c) for c in nondynamical_parameters],
        'nondynamical_parameters_units':
        [str(c) for c in nondynamical_parameters_units],
        'independent_variable':
        str(independent_variable),
        'independent_variable_units':
        str(independent_variable_units),
        'control_list': [str(x) for x in it.chain(controls)],
        'controls': [str(u) for u in controls],
        'hamiltonian':
        str(hamiltonian),
        'hamiltonian_units':
        str(hamiltonian_units),
        'num_states':
        len(reduced_states),
        'dHdu':
        str(dHdu),
        'bc_initial': [str(_) for _ in bc_initial],
        'bc_terminal': [str(_) for _ in bc_terminal],
        'control_options':
        control_law,
        'num_controls':
        len(controls)
    }

    states_2_constants_fn = [
        make_jit_fn([str(x) for x in original_states], str(c))
        for c in constants_of_motion_values
    ]
    states_2_states_fn = [
        make_jit_fn([str(x) for x in original_states], str(y))
        for y in reduced_states
    ]

    def guess_mapper(sol):
        n_c = len(constants_of_motion)
        if n_c == 0:
            return sol
        sol_out = Solution()
        sol_out.t = copy.copy(sol.t)
        sol_out.y = np.array([[fn(*sol.y[0]) for fn in states_2_states_fn]])
        sol_out.q = sol.q
        if len(quads) > 0:
            sol_out.q = -0.0 * np.array([np.ones((len(quads)))])
        sol_out.dynamical_parameters = sol.dynamical_parameters
        sol_out.dynamical_parameters[-n_c:] = np.array(
            [fn(*sol.y[0]) for fn in states_2_constants_fn])
        sol_out.nondynamical_parameters = sol.nondynamical_parameters
        sol_out.aux = sol.aux
        return sol_out

    return out, guess_mapper
Пример #6
0
Mat = sym.Matrix
Sym = sym.symbols
Half = Rat(1, 2)
Third = Rat(1, 3)
Quarter = Rat(1, 4)


def Rec(n):
    return Rat(1, n)


from sympy.diffgeom.rn import R2_r
from sympy.diffgeom import WedgeProduct
ex, ey = R2_r.base_vectors()
dx, dy = R2_r.base_oneforms()
print(WedgeProduct(dx, dy))
print(WedgeProduct(dx, dy)(ex, ey))

J = Mat([[Sym("J_{}{}".format(i, j)) for j in range(1, 3)]
         for i in range(1, 4)])
print_matrix(J)
print_matrix(J.T * J)


class k_vector:
    def __init__(self, n):
        self.n = n


def E(n, *vecs):
    assert (len(vecs) <= n)
Пример #7
0
m.z = rect.coord_function(2)
m.e_x = BaseVectorField(rect, 0)
m.e_y = BaseVectorField(rect, 1)
m.e_z = BaseVectorField(rect, 2)
m.dx = Differential(m.x)
m.dy = Differential(m.y)
m.dz = Differential(m.z)
omega_x = Function('omega_x')
omega_y = Function('omega_y')
omega_z = Function('omega_z')

m.r = polar.coord_function(0)
m.phi = polar.coord_function(1)
m.theta = polar.coord_function(2)
m.e_r = BaseVectorField(polar, 0)
m.e_phi = BaseVectorField(polar, 1)
m.e_theta = BaseVectorField(polar, 2)
m.dr = Differential(m.r)
m.dphi = Differential(m.phi)
m.dtheta = Differential(m.theta)

omega_r = Function('omega_r')
omega_phi = Function('omega_phi')
omega_theta = Function('omega_theta')

omega = omega_x(m.x, m.y, m.z) * WedgeProduct(m.dy, m.dz) + omega_y(
    m.x, m.y, m.z) * WedgeProduct(m.dz, m.dx) + omega_z(
        m.x, m.y, m.z) * WedgeProduct(m.dx, m.dy)
d_omega = Differential(omega)
pprint(d_omega)
Пример #8
0
def ocp_to_bvp(ocp, **kwargs):
    """
    Converts an OCP to a BVP using diffy G methods.

    :param ocp: An OCP.
    :return: bvp, map, map_inverse
    """

    logging.warning(
        '\'diffyg_deprecated\' method is deprecated and will be removed in a later version, use \'indirect\'.'
    )

    ws = init_workspace(ocp)
    problem_name = ws['problem_name']
    independent_variable = ws['independent_var']
    independent_variable_units = ws['independent_var_units']
    states = ws['states']
    states_rates = ws['states_rates']
    states_units = ws['states_units']
    controls = ws['controls']
    controls_units = ws['controls_units']
    constants = ws['constants']
    constants_units = ws['constants_units']
    constants_values = ws['constants_values']
    constants_of_motion = ws['constants_of_motion']
    constants_of_motion_values = ws['constants_of_motion_values']
    constants_of_motion_values_original = copy.deepcopy(
        constants_of_motion_values)
    constants_of_motion_units = ws['constants_of_motion_units']
    symmetries = ws['symmetries']
    constraints = ws['constraints']
    constraints_units = ws['constraints_units']
    constraints_lower = ws['constraints_lower']
    constraints_upper = ws['constraints_upper']
    constraints_activators = ws['constraints_activators']
    constraints_method = ws['constraints_method']
    switches = ws['switches']
    switches_values = ws['switches_values']
    switches_conditions = ws['switches_conditions']
    switches_tolerance = ws['switches_tolerance']
    parameters = ws['parameters']
    parameters_units = ws['parameters_units']
    initial_cost = ws['initial_cost']
    initial_cost_units = ws['initial_cost_units']
    terminal_cost = ws['terminal_cost']
    terminal_cost_units = ws['terminal_cost_units']
    path_cost = ws['path_cost']
    path_cost_units = ws['path_cost_units']

    if initial_cost != 0:
        cost_units = initial_cost_units
    elif terminal_cost != 0:
        cost_units = terminal_cost_units
    elif path_cost != 0:
        cost_units = path_cost_units * independent_variable_units
    else:
        raise ValueError(
            'Initial, path, and terminal cost functions are not defined.')
    """
    Deal with path constraints
    """
    for ii, c in enumerate(constraints['path']):
        if constraints_method['path'] is None:
            raise NotImplementedError

        if constraints_method['path'][ii].lower() == 'utm':
            path_cost += utm_path(c, constraints_lower['path'][ii],
                                  constraints_upper['path'][ii],
                                  constraints_activators['path'][ii])
        elif constraints_method['path'][ii].lower() == 'epstrig':
            path_cost += epstrig_path(c, constraints_lower['path'][ii],
                                      constraints_upper['path'][ii],
                                      constraints_activators['path'][ii])
            upper = constraints_upper['path'][ii]
            lower = constraints_lower['path'][ii]
            subber = dict(
                zip([constraints['path'][ii]],
                    [(upper - lower) / 2 * sympy.sin(constraints['path'][ii]) +
                     (upper + lower) / 2]))
            for ii in range(len(states_rates)):
                states_rates[ii] = states_rates[ii].subs(subber,
                                                         simultaneous=True)
        else:
            raise NotImplementedError('Unknown path constraint method \"' +
                                      str(constraints_method['path'][ii]) +
                                      '\"')

    dynamical_parameters = []
    """
    Deal with staging and switches
    """
    for ii in range(len(switches)):
        if isinstance(switches_values[ii], list):
            true_value = 0
            for jj in range(len(switches_values[ii])):
                temp_value = switches_values[ii][jj]
                for kk in range(len(switches_conditions[ii][jj])):
                    temp_value *= rash_mult(switches_conditions[ii][jj][kk],
                                            switches_tolerance[ii])
                true_value += temp_value
            switches_values[ii] = true_value
    """
    Make substitutions with the switches
    """
    switch_vars, switch_list, derivative_fn = process_quantities(
        switches, switches_values)
    for var in switch_vars.keys():
        initial_cost = initial_cost.subs(Symbol(var), switch_vars[var])
        path_cost = path_cost.subs(Symbol(var), switch_vars[var])
        terminal_cost = terminal_cost.subs(Symbol(var), switch_vars[var])
        for ii in range(len(states_rates)):
            states_rates[ii] = states_rates[ii].subs(Symbol(var),
                                                     switch_vars[var])

    Q = Manifold(states, 'State_Space')
    E = Manifold(states + controls, 'Input_Space')
    R = Manifold([independent_variable], 'Independent_Space')
    tau_Q = FiberBundle(Q, R, 'State_Bundle')
    tau_E = FiberBundle(E, R, 'Input_Bundle')
    J1tau_Q = JetBundle(tau_Q, 1, 'Jet_Bundle')
    num_states = len(states)
    num_states_total = len(J1tau_Q.vertical.base_coords)

    hamiltonian, hamiltonian_units, costates, costates_units = make_hamiltonian(
        states, states_rates, states_units, path_cost, cost_units)

    setx = dict(zip(states + costates, J1tau_Q.vertical.base_coords))
    vector_names = [Symbol('D_' + str(x)) for x in states]
    settangent = dict(
        zip(vector_names, J1tau_Q.vertical.base_vectors[:num_states]))

    # Change original terms to be written on manifolds so the diffy g calculations are handled properly
    states = [x.subs(setx, simultaneous=True) for x in states]
    states_rates = [x.subs(setx, simultaneous=True) for x in states_rates]
    costates = J1tau_Q.vertical.base_coords[num_states:]
    constants_of_motion_values = [
        x.subs(setx, simultaneous=True) for x in constants_of_motion_values
    ]
    constants_of_motion_values_original = [
        x.subs(setx, simultaneous=True)
        for x in constants_of_motion_values_original
    ]
    symmetries = [x.subs(setx, simultaneous=True) for x in symmetries]
    symmetries = [x.subs(settangent, simultaneous=True) for x in symmetries]
    constraints['initial'] = [
        x.subs(setx, simultaneous=True) for x in constraints['initial']
    ]
    constraints['terminal'] = [
        x.subs(setx, simultaneous=True) for x in constraints['terminal']
    ]
    initial_cost = initial_cost.subs(setx, simultaneous=True)
    terminal_cost = terminal_cost.subs(setx, simultaneous=True)

    hamiltonian = hamiltonian.subs(setx, simultaneous=True)
    dhdt = derivative_fn(hamiltonian, independent_variable)
    # if dhdt == 0:
    #     constants_of_motion = constants_of_motion + [Symbol('hamiltonian')]
    #     constants_of_motion_values = constants_of_motion_values + [hamiltonian]
    #     constants_of_motion_units = constants_of_motion_units + [hamiltonian_units]

    coparameters = make_costate_names(parameters)
    coparameters_units = [
        path_cost_units / parameter_units
        for parameter_units in parameters_units
    ]
    coparameters_rates = make_costate_rates(hamiltonian, parameters,
                                            coparameters, derivative_fn)

    quads = []
    quads_rates = []
    quads_units = []
    quads += coparameters
    quads_rates += coparameters_rates
    quads_units += coparameters_units

    pi = 0
    omega = 0
    for ii in range(num_states):
        # pi += WedgeProduct(J1tau_Q.base_vectors[ii], J1tau_Q.base_vectors[ii + num_states])
        pi += TensorProduct(J1tau_Q.base_vectors[ii], J1tau_Q.base_vectors[ii + num_states]) - \
              TensorProduct(J1tau_Q.base_vectors[ii + num_states], J1tau_Q.base_vectors[ii])
        omega += WedgeProduct(J1tau_Q.base_oneforms[ii],
                              J1tau_Q.base_oneforms[ii + num_states])

    state_costate_pairing = 0
    for ii in range(num_states):
        state_costate_pairing += TensorProduct(J1tau_Q.base_coords[ii + num_states]*J1tau_Q.base_vectors[ii]) + \
                                 TensorProduct(J1tau_Q.base_coords[ii]*J1tau_Q.base_vectors[ii + num_states])

    constant_2_units = {
        c: u
        for c, u in zip(constants_of_motion, constants_of_motion_units)
    }

    reduced_states = states + costates
    original_states = copy.copy(reduced_states)
    reduced_states_units = states_units + costates_units
    state_2_units = {
        x: u
        for x, u in zip(reduced_states, reduced_states_units)
    }

    X_H = pi.rcall(None, hamiltonian)
    equations_of_motion = [X_H.rcall(x) for x in J1tau_Q.vertical.base_coords]

    augmented_initial_cost, augmented_initial_cost_units, initial_lm_params, initial_lm_params_units =\
        make_augmented_cost(initial_cost, cost_units, constraints, constraints_units, location='initial')
    augmented_terminal_cost, augmented_terminal_cost_units, terminal_lm_params, terminal_lm_params_units =\
        make_augmented_cost(terminal_cost, cost_units, constraints, constraints_units, location='terminal')

    dV_cost_initial = J1tau_Q.verticalexteriorderivative(
        augmented_initial_cost)
    dV_cost_terminal = J1tau_Q.verticalexteriorderivative(
        augmented_terminal_cost)
    bc_initial = constraints['initial'] + \
        [costate + dV_cost_initial.rcall(D_x) for costate, D_x
         in zip(costates, J1tau_Q.vertical.base_vectors[:num_states])] + \
        [coparameter - derivative_fn(augmented_initial_cost, parameter) for parameter, coparameter
         in zip(parameters, coparameters)]
    bc_terminal = constraints['terminal'] + \
        [costate - dV_cost_terminal.rcall(D_x) for costate, D_x
         in zip(costates, J1tau_Q.vertical.base_vectors[:num_states])] + \
        [coparameter - derivative_fn(augmented_terminal_cost, parameter) for parameter, coparameter
         in zip(parameters, coparameters)]
    time_bc = make_time_bc(constraints, derivative_fn, hamiltonian,
                           independent_variable)

    if time_bc is not None:
        bc_terminal += [time_bc]
    dHdu = make_dhdu(hamiltonian, controls, derivative_fn)
    control_law = make_control_law(dHdu, controls)

    tf = sympify('_tf')
    # bc_terminal = [bc.subs(independent_variable, tf, simultaneous=True) for bc in bc_terminal]
    dynamical_parameters = parameters + [tf]
    dynamical_parameters_units = parameters_units + [
        independent_variable_units
    ]
    nondynamical_parameters = initial_lm_params + terminal_lm_params
    nondynamical_parameters_units = initial_lm_params_units + terminal_lm_params_units

    subalgebras = []
    if len(constants_of_motion) > 0:
        logging.debug('Checking commutation relations... ')
        num_consts = len(constants_of_motion)

        commutation_relations = [[None for _ in range(num_consts)]
                                 for _ in range(num_consts)]
        for ii, c1 in enumerate(constants_of_motion_values):
            for jj, c2 in enumerate(constants_of_motion_values):
                commutation_relations[ii][jj] = pi.rcall(c1, c2)

        for ii, c1 in enumerate(constants_of_motion_values):
            subalgebras.append({constants_of_motion[ii]})
            for jj in range(0, num_consts):
                if commutation_relations[ii][jj] != 0:
                    subalgebras[-1] |= {constants_of_motion[jj]}

        subalgebras = [
            gs for ii, gs in enumerate(subalgebras)
            if gs not in subalgebras[ii + 1:]
        ]
        reducible_subalgebras = [len(gs) == 1 for gs in subalgebras]
        logging.debug('Done. ' + str(sum(reducible_subalgebras)) + ' of ' +
                      str(len(subalgebras)) +
                      ' subalgebras are double reducible.')

    for subalgebra in subalgebras:
        constant_2_value = {
            c: v
            for c, v in zip(constants_of_motion, constants_of_motion_values)
        }
        dim = len(subalgebra)
        if dim > 1:
            raise NotImplementedError
        # G_name = 'G_' + str(subalgebra).replace('{','').replace('}','')
        # G = LieGroup(list(subalgebra), G_name)
        # h = constant_2_value[constants_of_motion[0]]

        logging.debug('Attempting reduction of ' + str(subalgebra) + '...')
        # M_r, phi = restrictor(M, dict([(x, constant_2_value[x]) for x in list(subalgebra)]))
        free_vars = set()
        const = dict([(x, constant_2_value[x]) for x in list(subalgebra)])
        for c in const.keys():
            free_vars |= const[c].atoms(reduced_states[0])

        eq_set = [c - const[c] for c in const.keys()]
        constants_sol = sympy.solve(eq_set,
                                    list(free_vars),
                                    dict=True,
                                    minimal=True,
                                    simplify=False)[0]

        # hamiltonian = phi.pullback(hamiltonian)

        # g_ii = 0
        # for ii in range(len(M_r.base_coords)):
        #     for jj in range(len(M_r.base_coords)):
        #         g_ii += TensorProduct(M_r.base_oneforms[ii], M_r.base_oneforms[jj])
        # omega = phi.pullback(omega)
        # # pi = M_r.sharp(omega)
        # constants_of_motion = [phi.pullback(c) for c in constants_of_motion]
        # dH = M_r.exteriorderivative(hamiltonian)
        # eoms = omega.rcall(None, M_r.sharp(dH))
        # breakpoint()
        # eps_c = omega.rcall(None, M_r.sharp(M_r.exteriorderivative(constants_of_motion[0])))
        # quad_field = eoms.rcall(M_r.sharp(omega.rcall(None, constants_of_motion[0])))
        # breakpoint()
        #
        # breakpoint()
        for x in constants_sol:
            reduced_states.remove(x)
            quads.append(state_costate_pairing.rcall(x))
            quant = [constant_2_value[c] for c in subalgebra][0]
            quads_rates.append(J1tau_Q.flat(X_H).rcall(pi.rcall(None, quant)))
            quads_units.append(state_2_units[state_costate_pairing.rcall(x)])
            reduced_states.remove(state_costate_pairing.rcall(x))

        temp = copy.copy(subalgebra)
        temp2 = copy.copy(temp)
        dynamical_parameters.append(temp.pop())
        dynamical_parameters_units.append(constant_2_units[temp2.pop()])

        hamiltonian = hamiltonian.subs(constants_sol, simultaneous=True)
        pi = pi.subs(constants_sol, simultaneous=True
                     )  # TODO: Also change the vectors and differential forms
        X_H = pi.rcall(None, hamiltonian)
        equations_of_motion = [X_H.rcall(x) for x in reduced_states]

        for ii in range(len(quads_rates)):
            quads_rates[ii] = quads_rates[ii].subs(constants_sol,
                                                   simultaneous=True)

        for ii in range(len(control_law)):
            for control in control_law[ii]:
                control_law[ii][control] = control_law[ii][control].subs(
                    constants_sol, simultaneous=True)

        for ii in range(len(constants_of_motion_values)):
            constants_of_motion_values[ii] = constants_of_motion_values[
                ii].subs(constants_sol, simultaneous=True)

        for ii in range(len(bc_initial)):
            bc_initial[ii] = bc_initial[ii].subs(constants_sol,
                                                 simultaneous=True)

        for ii in range(len(bc_terminal)):
            bc_terminal[ii] = bc_terminal[ii].subs(constants_sol,
                                                   simultaneous=True)

        logging.debug('Done.')

    # Generate the problem data
    control_law = [{str(u): str(law[u])
                    for u in law.keys()} for law in control_law]
    out = {
        'method':
        'diffyg',
        'problem_name':
        problem_name,
        'control_method':
        '',
        'consts': [str(k) for k in constants],
        'initial_cost':
        None,
        'initial_cost_units':
        None,
        'path_cost':
        None,
        'path_cost_units':
        None,
        'terminal_cost':
        None,
        'terminal_cost_units':
        None,
        'states': [str(x) for x in reduced_states],
        'states_units': [str(state_2_units[x]) for x in reduced_states],
        'states_rates': [str(tf * rate) for rate in equations_of_motion],
        'states_jac': [None, None],
        'quads': [str(x) for x in quads],
        'quads_rates': [str(tf * x) for x in quads_rates],
        'quads_units': [str(x) for x in quads_units],
        'path_constraints': [],
        'path_constraints_units': [],
        'constants': [str(c) for c in constants],
        'constants_units': [str(c) for c in constants_units],
        'constants_values': [float(c) for c in constants_values],
        'constants_of_motion': [str(c) for c in constants_of_motion],
        'dynamical_parameters': [str(c) for c in dynamical_parameters],
        'dynamical_parameters_units':
        [str(c) for c in dynamical_parameters_units],
        'nondynamical_parameters': [str(c) for c in nondynamical_parameters],
        'nondynamical_parameters_units':
        [str(c) for c in nondynamical_parameters_units],
        'control_list': [str(x) for x in it.chain(controls)],
        'controls': [str(u) for u in controls],
        'hamiltonian':
        str(hamiltonian),
        'hamiltonian_units':
        str(hamiltonian_units),
        'num_states':
        len(reduced_states),
        'dHdu': [str(x) for x in dHdu],
        'bc_initial': [str(_) for _ in bc_initial],
        'bc_terminal': [str(_) for _ in bc_terminal],
        'control_options':
        control_law,
        'num_controls':
        len(controls)
    }

    states_2_constants_fn = [
        make_jit_fn([str(x) for x in original_states + controls], str(c))
        for c in constants_of_motion_values_original
    ]
    states_2_reduced_states_fn = [
        make_jit_fn([str(x) for x in original_states], str(y))
        for y in reduced_states
    ]

    constants_2_states_fn = [
        make_jit_fn([str(x) for x in reduced_states + constants_of_motion],
                    str(y)) for y in constants_of_motion
    ]

    def guess_map(sol, _compute_control=None):
        if _compute_control is None:
            raise ValueError(
                'Guess mapper not properly set up. Bind the control law to keyword \'_compute_control\''
            )
        sol_out = copy.deepcopy(sol)
        nodes = len(sol.t)
        n_c = len(constants_of_motion)
        sol_out.t = copy.copy(sol.t / sol.t[-1])
        sol_out.y = np.array([[
            fn(*sol.y[ii], *sol.dual[ii]) for fn in states_2_reduced_states_fn
        ] for ii in range(sol.t.size)])
        sol_out.q = sol.q
        if len(quads) > 0:
            sol_out.q = -0.0 * np.array([np.ones((len(quads)))])
        sol_out.dynamical_parameters = np.hstack(
            (sol.dynamical_parameters, sol.t[-1],
             np.array([
                 fn(*sol.y[0], *sol.dual[0], *sol.u[0])
                 for fn in states_2_constants_fn
             ])))
        sol_out.nondynamical_parameters = np.ones(len(nondynamical_parameters))
        sol_out.u = np.array([]).reshape((nodes, 0))
        sol_out.const = sol.const
        return sol_out

    def guess_map_inverse(sol, _compute_control=None):
        if _compute_control is None:
            raise ValueError(
                'Guess mapper not properly set up. Bind the control law to keyword \'_compute_control\''
            )
        sol_out = copy.deepcopy(sol)
        sol_out.u = np.vstack([
            _compute_control(yi, None, sol.dynamical_parameters, sol.const)
            for yi in sol.y
        ])
        return sol_out

    return out, guess_map, guess_map_inverse
Пример #9
0
TensorProduct(R2.dx, R2.dy)(R2.e_y, R2.e_x)
TensorProduct(R2.dx, R2.x*R2.dy)(R2.x*R2.e_x, R2.e_y)
#You can nest tensor products.
tp1 = TensorProduct(R2.dx, R2.dy)
TensorProduct(tp1, R2.dx)(R2.e_x, R2.e_y, R2.e_x)
#You can make partial contraction for instance when ‘raising an index’. Putting None in the second argument of rcall means that the respective position in the tensor product is left as it is.
TP = TensorProduct
metric = TP(R2.dx, R2.dx) + 3*TP(R2.dy, R2.dy)
metric.rcall(R2.e_y, None)
# WedgeProduct Examples
from sympy import Function
from sympy.diffgeom.rn import R2
from sympy.diffgeom import WedgeProduct
from sympy import pprint

WedgeProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y)
WedgeProduct(R2.dx, R2.dy)(R2.e_y, R2.e_x)
WedgeProduct(R2.dx, R2.x*R2.dy)(R2.x*R2.e_x, R2.e_y)
#You can nest wedge products
wp1 = WedgeProduct(R2.dx, R2.dy)
WedgeProduct(wp1, R2.dx)(R2.e_x, R2.e_y, R2.e_x)
# LieDerivative Examples
from sympy.diffgeom import (LieDerivative, TensorProduct)
from sympy.diffgeom.rn import R2
LieDerivative(R2.e_x, R2.y)
LieDerivative(R2.e_x, R2.x)
LieDerivative(R2.e_x, R2.e_x)
# The Lie derivative of a tensor field by another tensor field is equal to their commutator:
LieDerivative(R2.e_x, R2.e_r)
LieDerivative(R2.e_x + R2.e_y, R2.x)
tp = TensorProduct(R2.dx, R2.dy)