/
ADSDComparison.kt
72 lines (55 loc) 路 2.64 KB
/
ADSDComparison.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package ai.hypergraph.kotlingrad.samples
import ai.hypergraph.kotlingrad.api.*
import java.math.BigDecimal
import kotlin.math.*
@Suppress("NonAsciiCharacters", "LocalVariableName", "RemoveRedundantBackticks")
fun main() {
val xs = (-1000.0..1000.0 step 7E-1).toList()
// val xs = (-1.0..1.0 step 0.0037).toList().toDoubleArray()
// Arbitrary precision (defaults to 30 significant figures)
var y = sin(x * cos(x * sin(x * cos(x))))
var `dy鈭昫x` = d(y) / d(x)
val bdvals = xs.map { BigDecimal(it) }.run {
val f = map { y(x to it).toDouble() }
val df = map { `dy鈭昫x`(x to it).toDouble() }
arrayOf(f, df)
}.map { it.toDoubleArray() }.toTypedArray()
// Automatic differentiation
val advals = xs.run {
fun x1(d: Double = 0.0, x: D = D(d)): D = grad { sin(x * cos(x * sin(x * cos(x)))) }
fun d1(d: Double = 0.0, x: D = D(d)): D {
grad { sin(x * cos(x * sin(x * cos(x)))) }
return x
}
arrayOf(map { x1(it).x }, map { d1(it).d }).map { it.toDoubleArray() }.toTypedArray()
}
// Symbolic differentiation
y = sin(x * cos(x * sin(x * cos(x))))
`dy鈭昫x` = d(y) / d(x)
// println("""
// y=$y
// dy/dx=$`dy鈭昫x`
// """.trimIndent())
val sdvals = xs.run { arrayOf(map { y(x to it).toDouble() }, map { `dy鈭昫x`(x to it).toDouble() }) }.map { it.toDoubleArray() }.toTypedArray()
// Numerical differentiation using centered differences
y = sin(x * cos(x * sin(x * cos(x))))
val h = 7E-13
`dy鈭昫x` = (y(x to x + h) - y(x to x - h)) / (2.0 * h)
val fdvals = xs.run { arrayOf(map { y(x to it).toDouble() }, map { `dy鈭昫x`(x to it).toDouble() }) }.map { it.toDoubleArray() }.toTypedArray()
val t = { i: Double, d: Double -> log10(abs(i - d)).let { if (it < -20) -20.0 else it } }
val errors = listOf(
// sdvals[1].zip(bdvals[1], t), // Appears indistinguishable on lets-plot
advals[1].zip(bdvals[1], t),
advals[1].zip(sdvals[1], t),
fdvals[1].zip(bdvals[1], t)
// Filter out values which hit the floor of numerical precision (effectively zero)
).map { it.run { var last = -14.0; map { d -> if (d <= -15.0) last else { last = d; d } } } }
// println("SD average error: ${errors[0].average()}")
// println("AD average error: ${errors[1].average()}")
// println("AD/SD average delta: ${errors[2].average()}")
for (i in xs.indices) println(xs[i].toString() + ",\t" + errors[0][i] + ",\t" + errors[1][i] + ",\t" + errors[2][i])
val title = "f(x) = sin(sin(sin(x)))) / x + sin(x) * x + cos(x) + x"
val labels = arrayOf("螖(SD, IP), 螖(AD, IP)", "螖(AD, SD)", "螖(FD, IP)")
val data = (labels.zip(errors) + ("x" to xs)).toMap()
data.plot2D(title, "comparison.svg", 0.2)
}