Производная функция в Swift?

Я хотел создать функцию, которая возвращает производную функции в точке для части моего приложения. Очевидно, это формальное определение предела.

введите здесь описание изображения

Но какая функция сможет вернуть производную функции в точке в Swift? Любые идеи для автоматического дифференцирования в Swift?


person modesitt    schedule 23.06.2015    source источник
comment
Шаг 1: Найдите способ представить исходную функцию в коде. Шаг 2: Убедитесь, что вы знаете все правила исчисления, необходимые для получения производной любой функции. Шаг 3: Если вы выполнили шаг 1 и шаг 2 и все еще застряли... возможно, вы вернетесь к переполнению стека.   -  person nhgrif    schedule 24.06.2015
comment
Что вы пробовали? Кроме того, вы действительно хотите вычислить фактическую производную или просто аппроксимировать ее, используя этот предельный алгоритм с очень маленьким значением h? Последнее тривиально. Первое нетривиально.   -  person Rob    schedule 24.06.2015
comment
В идеале должна быть вычислена фактическая производная. Алгоритм предела был бы намного проще.   -  person modesitt    schedule 24.06.2015
comment
Предполагая, что вы с удовольствием читаете о другом компьютерном языке с другой парадигмой, чтобы получить представление о том, как можно подойти к решению такого рода проблем, классическая «Структура и интерпретация компьютерных программ», в которой речь идет в основном на схеме функционального языка, имеет упрощенный вид. пример в разделе 2.3.2. Так что вам просто нужно прочитать туда. Это старая книга, поэтому она доступна бесплатно в формате PDF у ее первоначального издателя: web.mit. edu/alexmv/6.037/sicp.pdf   -  person Tommy    schedule 24.06.2015


Ответы (5)


Вот простой численный подход, основанный на приведенной выше формуле. Вы можете улучшить это:

derivativeOf принимает функцию fn и координату x x и возвращает числовую аппроксимацию производной fn в точке 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

Если вы планируете получить функцию от пользователя, это более сложная часть. Вы можете дать им несколько шаблонов на выбор:

  1. Полином третьего порядка: y = Ax^3 + Bx^2 + Cx + D
  2. функция греха: y = A * sin(B*x + C)
  3. функция cos: y = A * cos(B*x + C)
  4. n-й корень: y = x ^ (1/N)

и т. д. И тогда вы можете попросить их дать вам A, B, C, D или N

Давайте посмотрим, как это будет работать для многочлена 3-го порядка:

// 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
person vacawama    schedule 23.06.2015

Численный подход, вероятно, лучше всего подходит для вас, но если вас интересует аналитический подход, он очень прост для производных:

Объявим, что такое функция (предположим, у нас есть функции с одним параметром):

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

    func derivative() -> Function
}

Теперь давайте объявим основные функции:

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())
    }
}

Объявление функции не очень красивое:

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

но мы можем evaluate с рекурсией:

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
person Sulthan    schedule 04.06.2016

Я согласен с Коллином в том, что это огромная тема и что, вероятно, нет идеального решения. Однако для тех, кто согласен с эффективным, но несовершенным решением, ответ Вакавамы приятно прост. Если вы хотите использовать свою производную функцию с более математическим синтаксисом, вы можете определить оператор, к счастью, Swift делает это исключительно легко. Вот что я сделал:

Сначала я определил оператор для простого возврата функциональной версии производной. Мне лично нравится символ ➚ для производных, но очень большая часть существующих символов Unicode является допустимыми идентификаторами Swift.

postfix operator ➚ {}

postfix func ➚(f: Double -> Double) -> (Double -> Double) {
    let h = 0.00000000001
    func de(input: Double) -> Double {
        return (f(input + h) - f(input)) / h
    }
    return de
}

Далее давайте определим функцию, которую мы хотим дифференцировать:

func f(x: Double) -> Double {
    return x*x + 2*x + 3
}

Это можно использовать как таковое: f➚, которое вернет анонимную функцию, которая будет производной от f. Если вы хотите получить f в определенной точке (например, пусть x = 2), вы можете вызвать ее следующим образом: (f➚)(2)

Я решил, что мне нравятся операторы, поэтому я сделал еще один, чтобы этот синтаксис выглядел немного лучше:

infix operator ➚ { associativity left precedence 140 }
func ➚(left: Double -> Double, right: Double) -> Double {
    return (f➚)(right)
}

Выражение f➚2 теперь будет возвращать то же самое, что и (f➚)(2), просто его удобнее использовать, когда вы занимаетесь математикой.

Хороший вопрос, хорошие ответы всем, я просто подумал, что добавлю что-то дополнительное. Дайте знать, если у вас появятся вопросы!

person PyPiePi    schedule 25.02.2016

Не пытайтесь изобретать велосипед. Численное дифференцирование (численный анализ в целом) — это огромная тема (со многими возможными решениями * идеального нет), и люди, намного умнее нас обоих, уже придумали решения. Если вы действительно не заинтересованы во всех различных числовых дифференциальных алгоритмах (их компромиссах, реализациях и оптимизации), я бы предложил пойти другим путем. Вы говорите, что используете Swift? Почему бы не переключиться на Objective-C (я предполагаю, что вы пишете приложение для iOS или OSX). Если бы вы это сделали, вы могли бы обратиться к Научной библиотеке GNU (это C, библиотека С++). Может быть, вы можете вызывать код c/c++ прямо из Swift? ИДК однозначно.

Если вы действительно хотите, вы можете взглянуть на их код и посмотреть, как они реализовали свои решения для численного дифференцирования (хотя я бы не стал этого делать, если вы не готовы заняться сложной математикой).

реализация производной на C/C++ * вы могли бы попробовать поработать с этим (я сомневаюсь хотя это очень надежно). Если вам нужна точность и скорость, я сомневаюсь, что вы захотите сделать это и в Swift.

person Community    schedule 23.06.2015
comment
Swift может вызывать C и C++;) - person Kametrixom; 24.06.2015

Эта функция принимает функцию в качестве аргумента и возвращает ее производную функцию. h - небольшой сдвиг, порядок относительно дифференцирования. Он использует рекурсию для дифференцирования высокого порядка, поэтому он может быть не очень стабильным.

func differentiate(f:(Double)->(Double),_ h:Double=1e-4,_ order:Int=1)->(Double)->(Double){
var k=order
func diff(x: Double)-> Double{
    return (-f(x+2*h)+8*f(x+h)-8*f(x-h)+f(x-2*h))/12/h
    }
if(k==0){
    return f
    }
if(k<0){
    fatalError("Order must be non-negative")
    }
k=k-1
if(k>=1){
    return differentiate(diff,h*10,k)
    }
else{
    return diff
    }
}

print(differentiate({(x:Double)->(Double) in sin(x)},0.0001,4)(0))
person SBA    schedule 20.02.2016