Skip to content

Instantly share code, notes, and snippets.

@harrisonweinerman
Last active September 15, 2017 03:24
Show Gist options
  • Save harrisonweinerman/ca600476bbb21f92d73645b0b3494932 to your computer and use it in GitHub Desktop.
Save harrisonweinerman/ca600476bbb21f92d73645b0b3494932 to your computer and use it in GitHub Desktop.
//
// Calc IA
//
// Harrison Weinerman
//
// Spring 2016
//
// NOTE: Implicit differentiation support isn't complete. Does not yet implement product rule so be wary of differentiating unseparable equations beyond the first derivative. Also, evaluating derivatives at a point currerntly plugs in the same value for all variables.
//
import Foundation
enum Variable {
case x
case y
case constant
}
struct Monomial {
var coefficient : Double
var variable : Variable
var power : Double
var implicitDegree : Int
}
func analyticallyDifferentiate(expression : [Monomial], withRespectTo: Variable) -> [Monomial] {
var differentiated : [Monomial] = []
for mono in expression {
if mono.variable == withRespectTo {
//Can apply power rule
differentiated.append(powerRule(mono))
}
else if mono.variable != .constant {
//Implicitly differentiating
var x = mono
x.implicitDegree += 1
differentiated.append(powerRule(x))
}
}
return differentiated
}
func powerRule(expression: Monomial) -> Monomial {
if expression.implicitDegree == 0 && expression.variable != .constant {
if expression.power != 1 {
return Monomial(coefficient: expression.coefficient * expression.power,
variable: expression.variable,
power: expression.power - 1,
implicitDegree: 0)
}
else {
//0th power case returns 1
return Monomial(coefficient: expression.coefficient,
variable: .constant,
power: 1,
implicitDegree: 0)
}
}
else if expression.implicitDegree != 0 {
return Monomial(coefficient: expression.coefficient * expression.power,
variable: expression.variable,
power: expression.power - 1,
implicitDegree: expression.implicitDegree)
}
return Monomial(coefficient: 0, variable: .constant, power: 0, implicitDegree: 0)
}
func printExpression(expression: [Monomial]) -> String{
var printable = ""
var i = 0
for mono in expression {
//format signs
var coefficient = ""
if mono.coefficient >= 0 {
if i != 0 { coefficient = " + " }
coefficient += "\(mono.coefficient)"
}
else {
coefficient = " - \(abs(mono.coefficient))"
}
if mono.variable == .constant {
printable += "\(coefficient)"
}
else {
if mono.implicitDegree != 0 {
//format derivatives implicitly stated
var implicit = ""
for i in 1..<mono.implicitDegree+1 {
implicit += "'"
}
printable += "\(coefficient)"
if mono.power != 0 { printable += "\(mono.variable)^(\(mono.power))" }
printable += "\(mono.variable)\(implicit)"
}
else {
//format derivatives explicitly stated
printable += "\(coefficient)\(mono.variable)"
if mono.power != 1 { printable += "^(\(mono.power))" }
}
}
i+=1
}
print(printable)
return printable
}
func analyticallySolveDerivative(expression : [Monomial], value : Double) -> Double {
return evaluateExpression(analyticallyDifferentiate(expression, withRespectTo: .x), value: value)
}
func limitEstimateDerivative(expression : [Monomial], value : Double, delta : Double) -> Double {
let offset = delta / 2.0
let xUpper = value + offset
let xLower = value - offset
let upperBound = evaluateExpression(expression, value: xUpper)
let lowerBound = evaluateExpression(expression, value: xLower)
let slope = (upperBound - lowerBound) / (xUpper - xLower)
return slope
}
func evaluateExpression(expression: [Monomial], value : Double) -> Double {
var result = 0.0
for mono in expression {
var x = 1.0
if mono.variable != .constant { x = pow(value, mono.power) }
result += mono.coefficient * x
}
return result
}
var polynomial : [Monomial] = []
//Generate the expression you want to differentiate here. Code currently assumes expression setup here is set equal to y.
polynomial.append(Monomial(coefficient: 1, variable: .x, power: 1, implicitDegree: 0))
polynomial.append(Monomial(coefficient: 1, variable: .constant, power: 1, implicitDegree: 0))
polynomial.append(Monomial(coefficient: -6, variable: .x, power: 2, implicitDegree: 0))
polynomial.append(Monomial(coefficient: 4, variable: .x, power: -1, implicitDegree: 0))
polynomial.append(Monomial(coefficient: 2, variable: .x, power: 0.5, implicitDegree: 0))
//For example, the above 3 lines generates y = x + 1 - 6x^2 + 4x^-1 + 2x^0.5
let evaluatingAt = 2.0
let estimate = limitEstimateDerivative(polynomial, value: evaluatingAt, delta: 0.1)
let analytical = analyticallySolveDerivative(polynomial, value: evaluatingAt)
let error = 100 * (analytical - estimate) / analytical
let function = printExpression(polynomial)
let derivative = printExpression(analyticallyDifferentiate(polynomial, withRespectTo: .x))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment