Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

SwiftでRiemann球面を扱う

1.277 visualizaciones

Publicado el

Swiftに複素数を実装し、その後Riemann球面へ拡張します

Publicado en: Tecnología
  • Sé el primero en comentar

  • Sé el primero en recomendar esto

SwiftでRiemann球面を扱う

  1. 1. SpeeeKaigi資料 hayato_iida August 25, 2017 3:32 p.m. PJD飯田勇人 一応iOSエンジニア 最近はrails書いたり社内業務分析みたいな仕事 新宿のVR行きたい Swiftに複素数を実装する Riemann球面とは Riemann球面を実装する 演算子を新たに定義できる 既存型にprotocolを追加出来る 既存の演算子の処理を上書きする事もできる .swift SwiftでRiemann球面を扱う 自己紹介 導入 ちょっとした関数を計算したいときに何を使いますか? playgroundでSwiftをさくっと書きますよね? 色々値を代入したあとは複素数を代入したくなりますよ ね? Swiftには複素数がない! じゃ作ろう 目次 Swiftで数学を実装
  2. 2. // Intの足し算を掛け算に変える protocol X { static func +(a: Self, b: Self) -> Self } extension Int:X{ static func +(a: Int, b: Int) -> Int { return a * b } } 10 + 10 // 100 Complex型を作る 極座標形式で実装 .swift public struct Complex { public let angle: Double // 偏角 public let radius: Double // 絶対値 } 実部、虚部 .swift public var real: Double { get { return radius * cos(angle) } } public var imaginary: Double { get { return radius * sin(angle) } } 初期化 .swift public init(angle: Double, radius: Double) { self.radius = radius self.angle = angle } public init(real: Double, imaginary: Double) { let radius = sqrt(real * real + imaginary * imaginary) let angle = atan2(imaginary, real) self.init(angle: angle, radius: radius) } .swift 複素数を実装する 複素数の定義 便利に使うAPIを追加
  3. 3. Complex(angle: pi / 2, radius: 1) // i Complex(real: 1, imaginary: 1) // 1 + i 定数 .swift let pi = Double.pi let i = Complex(angle: pi / 2, radius: 1) 加算 減算 乗算 除算 加算 .swift extension Complex { static public func +(a: Complex, b: Complex) -> Complex { return Complex(real: a.real + b.real, imaginary: a.imaginary + b.imaginary) } } 減算 .swift extension Complex { static public func -(a: Complex, b: Complex) -> Complex { return Complex(real: a.real - b.real, imaginary: a.imaginary - b.imaginary) } } 乗算 .swift extension Complex { static public func *(a: Complex, b: Complex) -> Complex { return Complex(angle: a.angle + b.angle, radius: a.radius * b.radius) } } 除算 .swift 演算の定義 加減乗除を定義する Swift実装
  4. 4. extension Complex { static public func /(a: Complex, b: Complex) -> Complex { return Complex(angle: a.angle - b.angle, radius: a.radius / b.radius) } } .swift i * i // == -1 let x = Complex(angle:pi / 4, radius:1) let y = Complex(angle:-pi / 4, radius:1) x * y // == 1 .swift 1 + i 1 / i (1 + i) * (1.0 - i) 「Complex型に変換可能」なprotocol(Complexable)を定義 Int,Double,Floatにextensionで差し込む Complexable型の演算として定義しなおす Complex型同士の演算はできた 数値とComplex型の演算をしたい こうしたい 数値型と統合する 設計 クラス図 実装
  5. 5. .swift public protocol Complexable { func asComplex() -> Complex } extension Int: Complexable { public func asComplex() -> Complex {return Complex(Double(self))} } extension Float: Complexable { public func asComplex() -> Complex {return Complex(Double(self))} } extension Double: Complexable { public func asComplex() -> Complex {return Complex(self)} } public struct Complex: Complexable { ・・・ public func asComplex() -> Complex { return self } } .swift public struct Complex: Complexable { ・・・ static public func +(a: Complex, b: Complexable) -> Complex { return a.asComplex() + b.asComplex() } static public func +(a: Complexabe, b: Complex) -> Complex { return a.asComplex() + b.asComplex() } } 他の演算も同様に実装する Swift2製のが多い Riemann球面にしたい .swift 1/0 // 無限大? IEEE754「浮動小数点数算術標準」 できた 既存の複素数ライブラリの課題 Riemann球面 ゼロ除算
  6. 6. 浮動小数点のゼロ除算の定義が含まれる [https://ja.wikipedia.org/wiki/ゼロ除算] より 近づける方向によって発散の方向が違う 符号付きゼロ(+0,-0)を定義 +0 正の値から近づける .swift 1/+0 // infinity -0 負の値から近づける .swift 1/-0 // - infinity 前提として実数には∞,-∞という値は含まれない IEEE754 実数に∞,-∞の2点を追加した集合をFloatにする Floatが有限であることには一旦目をつぶる (1+i) / 0 = ∞ + ∞i // ? -(1+i) / 0 = -∞ + -∞i // ? ∞か-∞か 実数上での理解 複素数のゼロ除算をどう定義するか? 無限に存在する?
  7. 7. Rなら2点{∞,-∞}足せば済んだ 無限に点を追加する? しかも不可算無限個ある ∞を無限遠点として ただしこの無限遠点はRの時の∞ではないことに注意 Riemann球面 無限遠点の演算
  8. 8. すでにCの演算は実装済み 上記の無限遠点にまつわる演算を実装すればリーマン球面を実装したと言える TDDで実装する .swift let inf = Complex.infinity let nan = Complex.nan assert(inf != nan) assert(inf == inf) assert(inf != z) assert(inf + z == inf) assert(z + inf == inf) assert(0 + inf == inf + 0) assert(0 + inf == inf) assert((inf + inf).isNan) assert(inf - z == inf) assert(z - inf == inf) assert(0 - inf == inf - 0) assert(0 - inf == inf) assert((inf - inf).isNan) assert(z * inf == inf * z) assert(z * inf == inf) assert((0 * inf).isNan) assert((inf * 0).isNan) assert(inf * inf == inf) assert(i / 0 == inf) assert(z / 0 == inf) assert(1 / inf == 0) assert(0 / z == 0) assert((inf / inf).isNan) .swift extension Complex { static public let infinity = Complex(angle: Double.nan, radius: Double.infinit y) static public let nan = Complex(angle: Double.nan, radius: Double.nan) static public func +(a: Complex, b: Complex) -> Complex { if a.isInfinite && b.isInfinite { return Complex.nan } else if a.isInfinite || b.isInfinite { return Complex.infinity } else if a.isNan || b.isNan { return Complex.nan } return Complex(real: a.asComplex().real + b.asComplex().real, imaginary: a.a sComplex().imaginary + b.asComplex().imaginary) } } 他の演算子にも同様に実装して 実装 実装 実装 Swiftのライブラリにしました
  9. 9. github:SwiftRiemannSphere playgroundも同梱しているのでデモはそちらで 複素数をリーマン球面上の演算として扱いたい ただし実装としては計算に追加処理がかかるので計算機としては非効率 必要な範囲で選択的にリーマン球面を扱えるようにしたい ライブラリ化することで import したコードにだけ適用出来る Swift4対応で書いているので今後のSwiftの仕様変更にも強い 数学の定義をそのまま実装したので応用数学でも有効に使えるはず 総括

×