Last active
September 15, 2017 03:24
-
-
Save harrisonweinerman/ca600476bbb21f92d73645b0b3494932 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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