如何使用 Theano 求解常微分方程?

How do I use Theano to solve an ordinary differential equation?

这是我的 Python 代码:

import numpy as np


def spread_points_in_cube(n, dimensions=3, rng=None):
    from scipy.integrate import ode
    if rng is None:
        rng = np.random

    size = n * dimensions
    y0 = np.zeros((2 * size))
    y0[:size] = rng.uniform(0, 0.1, size=size)
    t0 = 0.0

    mean = np.zeros(dimensions)
    variance = np.eye(dimensions) * 0

    def decode(y):
        positions = np.remainder(y[:size].reshape((n, dimensions)), 1)
        velocities = y[size:].reshape((n, dimensions))
        return positions, velocities

    def get_forces(positions, velocities):
        delta_positions = positions[:, np.newaxis, :] - positions[np.newaxis, :, :]
        delta_positions = np.remainder(delta_positions + 0.5, 1) - 0.5  # wrapping
        distances = np.linalg.norm(delta_positions, axis=2, ord=2)
        distances += 1e-5
        pairwise_forces = delta_positions * (distances ** -3)[:, :, np.newaxis]
        magnetic_forces = np.sum(pairwise_forces, axis=1) / (n ** 2)

        velocity_mags = np.linalg.norm(velocities, axis=1, ord=2)
        drag_forces = -velocities * velocity_mags[:, np.newaxis]

        forces = magnetic_forces * 0.01 + drag_forces * 10.0
        return forces

    def f(t, y):
        positions, velocities = decode(y)
        forces = get_forces(positions, velocities)
        retval = np.zeros((2 * size))
        retval[:size] = velocities.reshape(size)
        retval[size:] = forces.reshape(size)
        return retval

    r = ode(f).set_integrator('vode', method='bdf')
    r.set_initial_value(y0, t0)
    t_max = 20
    dt = 1
    while r.successful() and r.t < t_max:
        positions, velocities = decode(r.y)
        forces = get_forces(positions, velocities)
        total_speed = np.sum(np.linalg.norm(velocities, axis=1, ord=2))
        total_force = np.sum(np.linalg.norm(forces, axis=1, ord=2))
        #print("\nt", r.t, "\np", positions, "\nv", velocities,
        #      "\nf", forces
        print(total_speed, total_force)
        if total_force < n * 1e-4:
            print("breaking")
            #break
        r.integrate(r.t + dt)
    print("converged after", r.t, total_speed, total_force)
    return positions
spread_points_in_cube(1000, 3)

是否可以使用Theano求解ODE?

这是 theano 中一个非常简单的 ode 求解器:

import numpy
import theano

# the right-hand side
def f(x, t):
    return x*(1-x)

x = theano.tensor.matrix() # why not a matrix
dt = theano.tensor.scalar()
t = theano.tensor.scalar()

x_next = x + f(x, t)*dt # implement your favourite RK method here!

# matrix of random initial values
# store it on the device
x_shared = theano.shared(numpy.random.rand(10, 10))

step = theano.function([t, dt], [],
        givens=[(x, x_shared)],
        updates=[(x_shared, x_next)],
        on_unused_input='warn')

t = 0.0
dt = 0.01

while t < 10:
    step(t, dt)
    t += dt
    # test halt condition here

print(x_shared.get_value()) # read back the result

希望对您有所帮助。 基本上你必须实现你的 Runge-Kutta 方法。

请注意,theano 的优势在于矢量化,因此我不会费心在 theano 中实现时间循环。这就是为什么我使用简单的 python while 循环,尽管我可以使用 theano scan。无论如何,根据您的目标,优化可能会很棘手。我不是 100% 相信 theano 是 ODE 求解器的不错选择。 Numpy 无论如何都会对力和位置矩阵进行矢量化,至少在 CPU 上是这样。通过 theano 实现,您可以利用 GPU,但这并不能保证加速。