Swift 3中的Lotka-Volterra模型

时间:2017-05-06 15:28:00

标签: swift3 pseudocode numerical-methods differential-equations conceptual

我正在尝试实现rk4函数来求解2个微分方程。我有这个实现Runge Kutta 4方法的代码:

//RK4 method
    func rk4_func(y_array: [Double], f_array: [(([Double], Double) -> Double)], t_val: Double, h_val: Double) -> [Double] {

        let length = y_array.count

        let t_half_step = t_val + h_val / 2.0
        let t_step = t_val + h_val

        var k1 = [Double](repeating: 0.0, count: length)
        var k2 = [Double](repeating: 0.0, count: length)
        var k3 = [Double](repeating: 0.0, count: length)
        var k4 = [Double](repeating: 0.0, count: length)
        var w = [Double](repeating: 0.0, count: length)
        var result = [Double](repeating: 0.0, count: length)

        for i in 0...length {
            k1[i] = h_val * f_array[i](y_array, t_val)
            w[i] = y_array[i] + k1[i]/2.0
        }

        for i in 0...length {
            k2[i] = h_val * f_array[i](w, t_half_step)
            w[i] = y_array[i] + k2[i]/2.0
        }

        for i in 0...length {
            k3[i] = h_val * f_array[i](w, t_half_step)
            w[i] = y_array[i] + k3[i]
        }

        for i in 0...length {
            k4[i] = h_val * f_array[i](w, t_step)
        }

        for i in 0...length {
            result[i] = y_array[i] + (k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i])/6.0
        }

        print(result)
        return result;

    }

但现在我需要实际 使用 ,这是我感到困惑的部分。如果有人有数值计算微分方程解的经验,那将有所帮助。

  1. 我需要哪些数组来提供此功能?

  2. t_val参数代表什么?这是最长时间吗?

  3. 输出如何解决"等式?

  4. 输出给了我什么?

  5. k1[i] = h_val * f_array[i](y_array, t_val)行中,f_array[i](y_array, t_val)是什么意思?是说对于f_array的i-th值,找到y_array的相应i-th值?那么t_val意味着什么?

  6. 作为参考,这里是需要解决的2个微分方程。上下文是我试图在数字上解决这些Lotka-Volterra模型,以在Xcode(Swift 3.x)中绘制时间序列和相空间图。

    enter image description here

    enter image description here

1 个答案:

答案 0 :(得分:0)

  1. y是当前状态的向量(实现为double数组)。 f_array是指向函数doty = f_array(y,t)的函数指针。

  2. t_val是当前状态的时间,h_val是时间步长。

  3. rk4_func的一次通话执行从t_valt_val+h_val

  4. 的时间步长
  5. 返回新状态y_next = rk4_func(y, f_array, t, h)

  6. 人们必须学习语言内部。希望,也就是说,为了使代码正常工作,f_array[0](y_array, t_val)的第一次调用计算完整的向量/数组值结果,并进一步调用只提取缓存结果的组件。

  7. https://github.com/pdemarest/swift-rk4找到的原始代码严重缺乏其RK4实现和语言标准的过时。在https://swift.sandbox.bluemix.net/测试的工作版本是

    import Foundation
    
    
    func RK4step(y: [Double], f: ([Double], Double) -> [Double], t: Double, h: Double) -> [Double] {
    
        let length = y.count
    
        var w = [Double](repeating: 0.0, count: length )
        var result = [Double](repeating: 0.0, count: length)
    
        let k1 = f(y,t)
        assert(k1.count == y.count, "States and Derivatives must be the same length")
        for i in 0..<length { w[i] = y[i] + 0.5*h*k1[i]  }
        let k2 = f(w, t+0.5*h)
        for i in 0..<length { w[i] = y[i] + 0.5*h*k2[i]  }
        let k3 = f(w,t+0.5*h)
        for i in 0..<length { w[i] = y[i] + h*k3[i]
        }
        let k4 = f(w,t+h)
    
        for i in 0..<length {
            result[i] = y[i] + (k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i])*h/6.0
        }
    
        return result;
    }
    
    
    
    func test_exp(){
        // Integrate: y' = y
        // y_0 = 1.0
        // from 0 to 2.0
    
        var y = [1.0]
    
        func deriv (y: [Double], t: Double) -> [Double] {
            return [ y[0] ]
        }
    
        var t = 0.0
        let h = 0.1
    
    
        while t < 2.0 {
            y = RK4step(y:y, f:deriv, t:t, h:h)
            t += h
            print("t: \(t), y: \(y[0]) exact: \(exp(t))\n")
        }
    
        let exact = exp(2.0)
        let error = abs(y[0] - exact)
    
        assert(error < pow(h, 4.0))
        print("y: \(y[0]) exact: \(exact) error: \(error)\n")
    
    }
    
    
    print("testing...\n")
    
    test_exp()
    

    对于Volterra-Lotka动力学,人们必须改变

        var y = [150.0, 5.0]
    
        let a = 5.0
        let b = 1.0
        let eps = 0.1
        let m = 5.0
    
        func deriv (y: [Double], t: Double) -> [Double] {
            let p = y[0]
            let q = y[1]
            return [ a*p-b*p*q, eps*b*p*q - m*q ]
        }
    

    具有正确修复的全局常量a,b,eps,m和二维初始值。在需要时添加打印语句。