// RUN: %target-run-simple-swift // REQUIRES: executable_test import StdlibUnittest import _Differentiation var InoutControlFlowTests = TestSuite("InoutControlFlow") // https://github.com/apple/swift/issues/55999 struct Model: Differentiable { var first: Float = 3 var second: Float = 1 mutating func outer() { inner() } mutating func inner() { self.second = self.first // Dummy no-op if block, required to introduce control flow. let x = 5 if x < 50 {} } } @differentiable(reverse) func loss(model: Model) -> Float{ var model = model model.outer() return model.second } InoutControlFlowTests.test("MutatingBeforeControlFlow") { var model = Model() let grad = gradient(at: model, of: loss) expectEqual(1, grad.first) expectEqual(0, grad.second) } // https://github.com/apple/swift/issues/56444 @differentiable(reverse) func adjust(model: inout Model, multiplier: Float) { model.first = model.second * multiplier // Dummy no-op if block, required to introduce control flow. let x = 5 if x < 50 {} } @differentiable(reverse) func loss2(model: Model, multiplier: Float) -> Float { var model = model adjust(model: &model, multiplier: multiplier) return model.first } InoutControlFlowTests.test("InoutParameterWithControlFlow") { var model = Model(first: 1, second: 3) let grad = gradient(at: model, 5.0, of: loss2) expectEqual(0, grad.0.first) expectEqual(5, grad.0.second) } @differentiable(reverse) func adjust2(multiplier: Float, model: inout Model) { model.first = model.second * multiplier // Dummy no-op if block, required to introduce control flow. let x = 5 if x < 50 {} } @differentiable(reverse) func loss3(model: Model, multiplier: Float) -> Float { var model = model adjust2(multiplier: multiplier, model: &model) return model.first } InoutControlFlowTests.test("LaterInoutParameterWithControlFlow") { var model = Model(first: 1, second: 3) let grad = gradient(at: model, 5.0, of: loss3) expectEqual(0, grad.0.first) expectEqual(5, grad.0.second) } runAllTests()