Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derivative function in swift?

I wanted to make a function that returns the derivative of a function at a point for part of my app. Obviously, this is the formal definition of a limit.

enter image description here

But what kind of a function would be able return the derivative of a function at a point in swift? Any ideas for automatic differentiation in swift?

like image 366
modesitt Avatar asked Jun 23 '15 23:06

modesitt


2 Answers

Here is a simple numerical approach based upon your formula above. You could improve upon this:

derivativeOf takes a function fn and an x-coordinate x and returns a numerical approximation of derivative of fn at x:

func derivativeOf(fn: (Double)->Double, atX x: Double) -> Double {
    let h = 0.0000001
    return (fn(x + h) - fn(x))/h
}

func x_squared(x: Double) -> Double {
    return x * x
}

// Ideal answer: derivative of x^2 is 2x, so at point 3 the answer is 6
let d1 = derivativeOf(fn: x_squared, atX: 3)  //  d1 = 6.000000087880153

// Ideal answer: derivative of sin is cos, so at point pi/2 the answer is 0
let d2 = derivativeOf(fn: sin, atX: .pi/2)  // d2 = -4.9960036108132044e-08

If you are planning on getting the function from the user, that is the tougher part. You could give them some templates to choose from:

  1. Third order polynomial: y = Ax^3 + Bx^2 + Cx + D
  2. sin function: y = A * sin(B*x + C)
  3. cos function: y = A * cos(B*x + C)
  4. nth root: y = x ^ (1/N)

etc. And then you could have them give you A, B, C, D, or N

Let's look at how that would work for a 3rd order polynomial:

// Take coefficients A, B, C, and D and return a function which
// computes f(x) = Ax^3 + Bx^2 + Cx + D
func makeThirdOrderPolynomial(A a: Double, B b: Double, C c: Double, D d: Double) -> ((Double) -> Double) {
    return { x in ((a * x + b) * x + c) * x + d }
}

// Get the coefficients from the user
let a = 5.0
let b = 3.0
let c = 1.0
let d = 23.0

// Use the cofficents to make the function
let f4 = makeThirdOrderPolynomial(A: a, B: b, C: c, D: d)

// Compute the derivative of f(x) = 5x^3 + 3x^2 + x + 23 at x = 5    
// Ideal answer: derivative is f'(x) = 15x^2 + 6x + 1, f'(5) = 406
let d4 = derivativeOf(fn: f4, atX: 5)  // d4 = 406.0000094341376
like image 143
vacawama Avatar answered Oct 30 '22 10:10

vacawama


The numerical approach is probably the best for you but if you are interested in the analytical approach, it's very simple for derivatives:

Let's declare what a function is (we suppose we have functions with one parameter):

protocol Function {
    func evaluate(value: Double) -> Double

    func derivative() -> Function
}

Now let's declare basic functions:

struct Constant : Function {
    let constant: Double

    func evaluate(value: Double) -> Double {
        return constant
    }

    func derivative() -> Function {
        return Constant(constant: 0)
    }
}

struct Parameter : Function {
    func evaluate(value: Double) -> Double {
        return value
    }

    func derivative() -> Function {
        return Constant(constant: 1)
    }
}

struct Negate : Function {
    let operand: Function

    func evaluate(value: Double) -> Double {
        return -operand.evaluate(value)
    }

    func derivative() -> Function {
        return Negate(operand: operand.derivative())
    }
}

struct Add : Function {
    let operand1: Function
    let operand2: Function

    func evaluate(value: Double) -> Double {
        return operand1.evaluate(value) + operand2.evaluate(value)
    }

    func derivative() -> Function {
        return Add(operand1: operand1.derivative(), operand2: operand2.derivative())
    }
}

struct Multiply : Function {
    let operand1: Function
    let operand2: Function

    func evaluate(value: Double) -> Double {
        return operand1.evaluate(value) * operand2.evaluate(value)
    }

    func derivative() -> Function {
        // f'(x) * g(x) + f(x) * g'(x)
        return Add(
            operand1: Multiply(operand1: operand1.derivative(), operand2: operand2),
            operand2: Multiply(operand1: operand1, operand2: operand2.derivative())
        )
    }
}

struct Divide : Function {
    let operand1: Function
    let operand2: Function

    func evaluate(value: Double) -> Double {
        return operand1.evaluate(value) / operand2.evaluate(value)
    }

    func derivative() -> Function {
        // (f'(x) * g(x) - f(x) * g'(x)) / (g(x)) ^ 2
        return Divide(
            operand1: Add(
                operand1: Multiply(operand1: operand1.derivative(), operand2: operand2),
                operand2: Negate(operand: Multiply(operand1: operand1, operand2: operand2.derivative()))
            ),
            operand2: Power(operand1: operand2, operand2: Constant(constant: 2))
        )
    }
}

struct Exponential : Function {
    let operand: Function

    func evaluate(value: Double) -> Double {
        return exp(operand.evaluate(value))
    }

    func derivative() -> Function {
        return Multiply(
            operand1: Exponential(operand: operand),
            operand2: operand.derivative()
        )
    }
}

struct NaturalLogarithm : Function {
    let operand: Function

    func evaluate(value: Double) -> Double {
        return log(operand.evaluate(value))
    }

    func derivative() -> Function {
        return Multiply(
            operand1: Divide(operand1: Constant(constant: 1), operand2: operand),
            operand2: operand.derivative()
        )
    }
}

struct Power : Function {
    let operand1: Function
    let operand2: Function

    func evaluate(value: Double) -> Double {
        return pow(operand1.evaluate(value), operand2.evaluate(value))
    }

    func derivative() -> Function {
        // x ^ y = e ^ ln (x ^ y) = e ^ (y * ln x)

        let powerFn = Exponential(
            operand: Multiply (
                operand1: operand2,
                operand2: NaturalLogarithm(operand: operand1)
            )
        )

        return powerFn.derivative()
    }
}

struct Sin: Function {
    let operand: Function

    func evaluate(value: Double) -> Double {
        return sin(operand.evaluate(value))
    }

    func derivative() -> Function {
        // cos(f(x)) * f'(x)
        return Multiply(operand1: Cos(operand: operand), operand2: operand.derivative())
    }
}

struct Cos: Function {
    let operand: Function

    func evaluate(value: Double) -> Double {
        return cos(operand.evaluate(value))
    }

    func derivative() -> Function {
        // - sin(f(x)) * f'(x)
        return Multiply(operand1: Negate(operand: Sin(operand: operand)), operand2: operand.derivative())
    }
}

The declaration of a function is not very nice:

let xSquared = Power(operand1: Parameter(), operand2: Constant(constant: 2))

but we can evaluate with recursion:

print(xSquared.evaluate(15))  // f(15) = 225
print(xSquared.derivative().evaluate(15))  // f'(15) = 2 * 15 = 30
print(xSquared.derivative().derivative().evaluate(15))  // f''(15) = 2
print(xSquared.derivative().derivative().derivative().evaluate(15))  // f'''(15) = 0
like image 25
Sulthan Avatar answered Oct 30 '22 08:10

Sulthan