mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
316 lines
9.2 KiB
Swift
316 lines
9.2 KiB
Swift
//===--- TgmathDerivatives.swift.gyb --------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// This file defines derivatives for tgmath functions.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Swift
|
|
|
|
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)
|
|
#if canImport(tgmath_h)
|
|
import tgmath_h
|
|
#else
|
|
import Darwin.C.tgmath
|
|
#endif
|
|
#elseif canImport(Musl)
|
|
import Musl
|
|
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(PS4) || os(Cygwin) || os(Haiku)
|
|
import Glibc
|
|
#elseif os(WASI)
|
|
import WASILibc
|
|
#elseif os(Windows)
|
|
import CRT
|
|
#elseif canImport(Android)
|
|
import Android
|
|
#else
|
|
#error("Unsupported platform")
|
|
#endif
|
|
|
|
%for T in ['T', 'Double']: # Prevents name collisions with system math library
|
|
% generic_signature = '<T: FloatingPoint & Differentiable>' if T == 'T' else ''
|
|
% constraint = 'where T == T.TangentVector' if T == 'T' else ''
|
|
@inlinable
|
|
@derivative(of: fma)
|
|
func _jvpFma${generic_signature} (
|
|
_ x: ${T},
|
|
_ y: ${T},
|
|
_ z: ${T}
|
|
) -> (value: ${T}, differential: (${T}, ${T}, ${T}) -> ${T}) ${constraint} {
|
|
return (fma(x, y, z), { (dx, dy, dz) in dx * y + dy * x + dz })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: fma)
|
|
func _vjpFma${generic_signature} (
|
|
_ x: ${T},
|
|
_ y: ${T},
|
|
_ z: ${T}
|
|
) -> (value: ${T}, pullback: (${T}) -> (${T}, ${T}, ${T})) ${constraint} {
|
|
return (fma(x, y, z), { v in (v * y, v * x, v) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: remainder)
|
|
func _jvpRemainder${generic_signature} (
|
|
_ x: ${T},
|
|
_ y: ${T}
|
|
) -> (value: ${T}, differential: (${T}, ${T}) -> ${T}) ${constraint} {
|
|
fatalError("""
|
|
Unimplemented JVP for 'remainder(_:)'. \
|
|
https://bugs.swift.org/browse/TF-1108 tracks this issue
|
|
""")
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: remainder)
|
|
func _vjpRemainder${generic_signature} (
|
|
_ x: ${T},
|
|
_ y: ${T}
|
|
) -> (value: ${T}, pullback: (${T}) -> (${T}, ${T})) ${constraint} {
|
|
return (remainder(x, y), { v in (v, -v * ((x / y).rounded(.toNearestOrEven))) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: fmod)
|
|
func _jvpFmod${generic_signature} (
|
|
_ x: ${T},
|
|
_ y: ${T}
|
|
) -> (value: ${T}, differential: (${T}, ${T}) -> ${T}) ${constraint} {
|
|
fatalError("""
|
|
Unimplemented JVP for 'fmod(_:)'. \
|
|
https://bugs.swift.org/browse/TF-1108 tracks this issue
|
|
""")
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: fmod)
|
|
func _vjpFmod${generic_signature} (
|
|
_ x: ${T},
|
|
_ y: ${T}
|
|
) -> (value: ${T}, pullback: (${T}) -> (${T}, ${T})) ${constraint} {
|
|
return (fmod(x, y), { v in (v, -v * ((x / y).rounded(.towardZero))) })
|
|
}
|
|
|
|
% for derivative_kind in ['jvp', 'vjp']:
|
|
% linear_map_kind = 'differential' if derivative_kind == 'jvp' else 'pullback'
|
|
@inlinable
|
|
@derivative(of: sqrt)
|
|
func _${derivative_kind}Sqrt${generic_signature} (
|
|
_ x: ${T}
|
|
) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) ${constraint} {
|
|
let value = sqrt(x)
|
|
return (value, { v in v / (2 * value) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: ceil)
|
|
func _${derivative_kind}Ceil${generic_signature} (
|
|
_ x: ${T}
|
|
) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) ${constraint} {
|
|
return (ceil(x), { v in 0 })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: floor)
|
|
func _${derivative_kind}Floor${generic_signature} (
|
|
_ x: ${T}
|
|
) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) ${constraint} {
|
|
return (floor(x), { v in 0 })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: round)
|
|
func _${derivative_kind}Round${generic_signature} (
|
|
_ x: ${T}
|
|
) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) ${constraint} {
|
|
return (round(x), { v in 0 })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: trunc)
|
|
func _${derivative_kind}Trunc${generic_signature} (
|
|
_ x: ${T}
|
|
) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) ${constraint} {
|
|
return (trunc(x), { v in 0 })
|
|
}
|
|
% end # for derivative_kind in ['jvp', 'vjp']:
|
|
%end # for T in ['T', 'Double']:
|
|
|
|
// Unary functions
|
|
%for derivative_kind in ['jvp', 'vjp']:
|
|
% linear_map_kind = 'differential' if derivative_kind == 'jvp' else 'pullback'
|
|
% for T in ['Float', 'Double', 'Float80']:
|
|
% if T == 'Float80':
|
|
#if !(os(Windows) || os(Android) || ($Embedded && !os(Linux) && !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)))) && (arch(i386) || arch(x86_64))
|
|
% end
|
|
@inlinable
|
|
@derivative(of: exp)
|
|
func _${derivative_kind}Exp(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
let value = exp(x)
|
|
return (value, { v in value * v })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: exp2)
|
|
func _${derivative_kind}Exp2(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
let value = exp2(x)
|
|
return (value, { v in v * ${T}(M_LN2) * value })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: log)
|
|
func _${derivative_kind}Log(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (log(x), { v in v / x })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: log10)
|
|
func _${derivative_kind}Log10(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (log10(x), { v in v * ${T}(M_LOG10E) / x })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: log2)
|
|
func _${derivative_kind}Log2(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (log2(x), { v in v / (${T}(M_LN2) * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: sin)
|
|
func _${derivative_kind}Sin(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (sin(x), { v in v * cos(x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: cos)
|
|
func _${derivative_kind}Cos(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (cos(x), { v in -v * sin(x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: tan)
|
|
func _${derivative_kind}Tan(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
let value = tan(x)
|
|
return (value, { v in v * (1 + value * value) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: asin)
|
|
func _${derivative_kind}Asin(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (asin(x), { v in v / sqrt(1 - x * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: acos)
|
|
func _${derivative_kind}Acos(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (acos(x), { v in -v / sqrt(1 - x * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: atan)
|
|
func _${derivative_kind}Atan(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (atan(x), { v in v / (1 + x * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: sinh)
|
|
func _${derivative_kind}Sinh(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (sinh(x), { v in v * cosh(x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: cosh)
|
|
func _${derivative_kind}Cosh(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (cosh(x), { v in v * sinh(x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: tanh)
|
|
func _${derivative_kind}Tanh(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
let value = tanh(x)
|
|
return (value, { v in v * (1 - value * value) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: asinh)
|
|
func _${derivative_kind}Asinh(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (asinh(x), { v in v / sqrt(1 + x * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: acosh)
|
|
func _${derivative_kind}Acosh(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (acosh(x), { v in v / sqrt(x * x - 1) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: atanh)
|
|
func _${derivative_kind}Atanh(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (atanh(x), { v in v / (1 - x * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: expm1)
|
|
func _${derivative_kind}Expm1(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (expm1(x), { v in exp(x) * v })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: log1p)
|
|
func _${derivative_kind}Log1p(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (log1p(x), { v in v / (x + 1) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: erf)
|
|
func _${derivative_kind}Erf(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (erf(x), { v in v * ${T}(M_2_SQRTPI) * exp(-x * x) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: erfc)
|
|
func _${derivative_kind}Erfc(_ x: ${T}) -> (value: ${T}, ${linear_map_kind}: (${T}) -> ${T}) {
|
|
return (erfc(x), { v in v * -${T}(M_2_SQRTPI) * exp(-x * x) })
|
|
}
|
|
|
|
% if T == 'Float80':
|
|
#endif
|
|
% end # if T == 'Float80':
|
|
% end # for T in ['Float', 'Double', 'Float80']:
|
|
%end # for derivative_kind in ['jvp', 'vjp']:
|
|
|
|
// Binary functions
|
|
%for T in ['Float', 'Double', 'Float80']:
|
|
% if T == 'Float80':
|
|
#if !(os(Windows) || os(Android) || ($Embedded && !os(Linux) && !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)))) && (arch(i386) || arch(x86_64))
|
|
% end
|
|
@inlinable
|
|
@derivative(of: pow)
|
|
func _vjpPow(_ x: ${T}, _ y: ${T}) -> (value: ${T}, pullback: (${T}) -> (${T}, ${T})) {
|
|
let value = pow(x, y)
|
|
return (value, { v in (
|
|
v * y * pow(x, y - 1), v * value * log(x.isLessThanOrEqualTo(0) ? ${T}(1) : x)
|
|
) })
|
|
}
|
|
|
|
@inlinable
|
|
@derivative(of: pow)
|
|
func _jvpPow(_ x: ${T}, _ y: ${T}) -> (value: ${T}, differential: (${T}, ${T}) -> ${T}) {
|
|
let value = pow(x, y)
|
|
return (value, { (dx, dy) in
|
|
dx * y * pow(x, y - 1) + dy * value * log(x.isLessThanOrEqualTo(0) ? ${T}(1) : x)
|
|
})
|
|
}
|
|
% if T == 'Float80':
|
|
#endif
|
|
% end # if T == 'Float80':
|
|
%end # for T in ['Float', 'Double', 'Float80']:
|