Files
kraken/koka_bench/swift/deriv.swift
2022-05-19 00:43:27 -04:00

177 lines
3.7 KiB
Swift

indirect enum Expr {
case Val(Int64)
case Var(String)
case Add(Expr, Expr)
case Mul(Expr, Expr)
case Pow(Expr, Expr)
case Ln(Expr)
}
func pown(_ a : Int64, _ n : Int64) -> Int64 {
if n == 0 {
return 1
} else if n == 1 {
return a
} else {
let b = pown(a, n/2)
if n % 2 == 0 {
return b*b*a
} else {
return b*b
}
}
}
func add (_ e1 : Expr, _ e2 : Expr) -> Expr {
switch (e1, e2) {
case let (.Val(n), .Val(m)) :
return .Val(n+m)
case let (.Val(0), f):
return f
case let (f, .Val(0)):
return f
case let (f, .Val(n)):
return add(.Val(n), f)
case let (.Val(n), .Add(.Val(m), f)):
return add(.Val(n+m), f)
case let (f, .Add(.Val(n), g)):
return add(.Val(n), add(f, g))
case let (.Add(f, g), h):
return add(f, add(g, h))
default:
return .Add(e1, e2)
}
}
func mul (_ e1 : Expr, _ e2 : Expr) -> Expr {
switch (e1, e2) {
case let (.Val(n), .Val(m)):
return .Val(n*m)
case (.Val(0), _):
return .Val(0)
case (_, .Val(0)):
return .Val(0)
case let (.Val(1), f):
return f
case let (f, .Val(1)):
return f
case let (f, .Val(n)):
return mul(.Val(n), f)
case let (.Val(n), .Mul(.Val(m), f)):
return mul(.Val(n*m), f)
case let (f, .Mul(.Val(n), g)):
return mul(.Val(n), mul(f, g))
case let (.Mul(f, g), h):
return mul(f, mul(g, h))
default:
return .Mul(e1, e2)
}
}
func pow (_ e1 : Expr, _ e2 : Expr) -> Expr {
switch (e1, e2) {
case let (.Val(m), .Val(n)):
return .Val(pown(m, n))
case (_, .Val(0)):
return .Val(1)
case let (f, .Val(1)):
return f
case (.Val(0), _):
return .Val(0)
default:
return .Pow(e1, e2)
}
}
func ln (_ e : Expr) -> Expr {
switch e {
case .Val(1):
return .Val(0)
default:
return .Ln(e)
}
}
func d (_ x : String, _ e : Expr) -> Expr {
switch e {
case .Val(_):
return .Val(0)
case let .Var(y):
if x == y {
return .Val(1)
} else {
return .Val(0)
}
case let .Add(f, g):
return add(d(x, f), d(x, g))
case let .Mul(f, g):
return add(mul(f, d(x, g)), mul(g, d(x, f)))
case let .Pow(f, g):
return mul(pow(f, g), add(mul(mul(g, d(x, f)), pow(f, .Val(-1))), mul(ln(f), d(x, g))))
case let .Ln(f):
return mul(d(x, f), pow(f, .Val(-1)))
}
}
func toString (_ e : Expr) -> String {
switch e {
case let .Val(n):
return String(n)
case let .Var(x):
return x
case let .Add(f, g):
return "(" + toString(f) + " + " + toString(g) + ")"
case let .Mul(f, g):
return "(" + toString(f) + " * " + toString(g) + ")"
case let .Pow(f, g):
return "(" + toString(f) + " ^ " + toString(g) + ")"
case let .Ln(f):
return "ln(" + toString(f) + ")"
}
}
func count (_ e : Expr) -> UInt32 {
switch e {
case .Val(_):
return 1
case .Var(_):
return 1
case let .Add(f, g):
return count(f) + count(g)
case let .Mul(f, g):
return count(f) + count(g)
case let .Pow(f, g):
return count(f) + count(g)
case let .Ln(f):
return count(f)
}
}
func nest_aux (_ s : UInt32, _ f : (_ n : UInt32, _ e : Expr) -> Expr, _ n : UInt32, _ x : Expr) -> Expr {
if n == 0 {
return x
} else {
let x = f(s - n, x)
return nest_aux(s, f, n-1, x)
}
}
func nest (_ f : (_ n : UInt32, _ e : Expr) -> Expr, _ n : UInt32, _ e : Expr) -> Expr {
return nest_aux(n, f, n, e)
}
func deriv (_ i : UInt32, _ f : Expr) -> Expr {
let e = d("x", f)
print(i+1, " count: ", count(e))
return e
}
var num: UInt32? = 10
if CommandLine.arguments.count >= 2 {
num = UInt32(CommandLine.arguments[1])
}
let x = Expr.Var("x")
let f = pow(x, x)
let e = nest(deriv, num!, f)