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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
// RUN: %target-run-simple-swiftgyb(-Xfrontend -enable-experimental-forward-mode-differentiation)
// REQUIRES: executable_test
#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64))
typealias TestLiteralType = Float80
#else
typealias TestLiteralType = Double
#endif
import _Differentiation
import StdlibUnittest
var FloatingPointDerivativeTests = TestSuite("FloatingPointDerivatives")
func expectEqualWithTolerance<T>(_ expected: TestLiteralType, _ actual: T,
ulps allowed: T = 3,
file: String = #file, line: UInt = #line
) where T: BinaryFloatingPoint {
if actual == T(expected) || actual.isNaN && expected.isNaN {
return
}
// Compute error in ulp, compare to tolerance.
let absoluteError = T(abs(TestLiteralType(actual) - expected))
let ulpError = absoluteError / T(expected).ulp
expectTrue(ulpError <= allowed,
"\(actual) != \(expected) as \(T.self)" +
"\n \(ulpError)-ulp error exceeds \(allowed)-ulp tolerance.",
file: file, line: line)
}
%for Self in ['Float', 'Double', 'Float80']:
%if Self == 'Float80':
#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64))
%end
%for Other in ['Float', 'Double', 'Float80']:
%if Other == 'Float80':
#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64))
%end
FloatingPointDerivativeTests.test("${Self}.init(_:${Other})") {
expectEqual(1, gradient(at: ${Other}(4), of: ${Self}.init(_:)))
expectEqual(10, pullback(at: ${Other}(4), of: ${Self}.init(_:))(${Self}(10)))
expectEqual(1, derivative(at: ${Other}(4), of: ${Self}.init(_:)))
expectEqual(10, differential(at: ${Other}(4), of: ${Self}.init(_:))(${Other}(10)))
}
%if Other == 'Float80':
#endif
%end
%end # for Other in ['Float', 'Double', 'Float80']:
FloatingPointDerivativeTests.test("${Self}.+") {
expectEqual((1, 1), gradient(at: ${Self}(4), ${Self}(5), of: +))
expectEqual((10, 10), pullback(at: ${Self}(4), ${Self}(5), of: +)(${Self}(10)))
expectEqual(2, derivative(at: ${Self}(4), ${Self}(5), of: +))
expectEqual(20, differential(at: ${Self}(4), ${Self}(5), of: +)(${Self}(10), ${Self}(10)))
}
FloatingPointDerivativeTests.test("${Self}.-") {
expectEqual((1, -1), gradient(at: ${Self}(4), ${Self}(5), of: -))
expectEqual((10, -10), pullback(at: ${Self}(4), ${Self}(5), of: -)(${Self}(10)))
expectEqual(0, derivative(at: ${Self}(4), ${Self}(5), of: -))
expectEqual(-5, differential(at: ${Self}(4), ${Self}(5), of: -)(${Self}(5), ${Self}(10)))
}
FloatingPointDerivativeTests.test("${Self}.*") {
expectEqual((5, 4), gradient(at: ${Self}(4), ${Self}(5), of: *))
expectEqual((50, 40), pullback(at: ${Self}(4), ${Self}(5), of: *)(${Self}(10)))
expectEqual(9, derivative(at: ${Self}(4), ${Self}(5), of: *))
expectEqual(90, differential(at: ${Self}(4), ${Self}(5), of: *)(${Self}(10), ${Self}(10)))
}
FloatingPointDerivativeTests.test("${Self}./") {
do {
let (dx, dy) = gradient(at: ${Self}(4), ${Self}(5), of: /)
expectEqual(0.2, dx)
expectEqual(-0.16, dy)
}
do {
let (dx, dy) = pullback(at: ${Self}(4), ${Self}(5), of: /)(${Self}(10))
expectEqual(2, dx)
expectEqualWithTolerance(-1.6, dy)
}
expectEqualWithTolerance(0.04, derivative(at: ${Self}(4), ${Self}(5), of: /))
expectEqual(90, differential(at: ${Self}(4), ${Self}(5), of: *)(${Self}(10), ${Self}(10)))
}
FloatingPointDerivativeTests.test("${Self}.squareRoot") {
expectEqual(0.5, gradient(at: 1, of: { $0.squareRoot() }))
expectEqual(0.25, gradient(at: 4, of: { $0.squareRoot() }))
}
FloatingPointDerivativeTests.test("${Self}.addingProduct") {
expectEqual((1, 2, 3), gradient(at: ${Self}(10), 3, 2, of: { $0.addingProduct($1, $2) }))
expectEqual((2, 4, 6), pullback(at: ${Self}(10), 3, 2, of: { $0.addingProduct($1, $2) })(2))
}
FloatingPointDerivativeTests.test("${Self}.minimum") {
expectEqual((1.0, 0.0), gradient(at: ${Self}(1), ${Self}(2), of: { ${Self}.minimum($0, $1) }))
expectEqual((1.0, 0.0), gradient(at: ${Self}(1), ${Self}(1), of: { ${Self}.minimum($0, $1) }))
expectEqual((0.0, 1.0), gradient(at: ${Self}(2), ${Self}(1), of: { ${Self}.minimum($0, $1) }))
expectEqual((1.0, 0.0), gradient(at: ${Self}(1), .nan, of: { ${Self}.minimum($0, $1) }))
expectEqual((0.0, 1.0), gradient(at: .nan, ${Self}(1), of: { ${Self}.minimum($0, $1) }))
}
FloatingPointDerivativeTests.test("${Self}.maximum") {
expectEqual((0.0, 1.0), gradient(at: ${Self}(1), ${Self}(2), of: { ${Self}.maximum($0, $1) }))
expectEqual((0.0, 1.0), gradient(at: ${Self}(1), ${Self}(1), of: { ${Self}.maximum($0, $1) }))
expectEqual((1.0, 0.0), gradient(at: ${Self}(2), ${Self}(1), of: { ${Self}.maximum($0, $1) }))
expectEqual((1.0, 0.0), gradient(at: ${Self}(1), .nan, of: { ${Self}.maximum($0, $1) }))
expectEqual((0.0, 1.0), gradient(at: .nan, ${Self}(1), of: { ${Self}.maximum($0, $1) }))
}
%if Self == 'Float80':
#endif
%end
%end # for Self in ['Float', 'Double', 'Float80']:
runAllTests()
|