├── Sources └── Anomalii │ ├── Anomalii.swift │ ├── ScalarValued.swift │ ├── General.swift │ ├── VectorValued.swift │ ├── Terminal.swift │ ├── Random.swift │ ├── Populator.swift │ ├── Traversal.swift │ ├── ScalarOperator.swift │ ├── Value.swift │ ├── Solver.swift │ ├── Orator.swift │ ├── Expression.swift │ ├── Operator.swift │ ├── Variable.swift │ ├── VectorOperator.swift │ ├── Mutator.swift │ ├── Constant.swift │ └── Evolver.swift ├── Tests ├── LinuxMain.swift └── AnomaliiTests │ ├── PopulatorTests.swift │ ├── CodableTests.swift │ ├── OratorTests.swift │ ├── RegressionTests.swift │ ├── StandardMutatorTests.swift │ ├── ExpressionTests.swift │ └── MultidimensionalOptimizationTests.swift ├── Anomalii.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ ├── Anomalii-Package.xcscheme │ │ ├── AnomaliiPackageTests.xcscheme │ │ └── AnomaliiPackageDescription.xcscheme ├── Anomalii_Info.plist ├── AnomaliiTests_Info.plist └── project.pbxproj ├── Package.swift ├── LICENSE ├── README.md └── .gitignore /Sources/Anomalii/Anomalii.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import AnomaliiTests 3 | 4 | XCTMain([ 5 | testCase(AnomaliiTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SchemeUserState 5 | 6 | Anomalii-Package.xcscheme 7 | 8 | 9 | SuppressBuildableAutocreation 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Sources/Anomalii/ScalarValued.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scalar.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | public protocol ScalarValued: Expression { 9 | } 10 | 11 | public extension ScalarValued { 12 | public static var outputValueKind: Value.Kind { return .scalar } 13 | } 14 | 15 | public extension ScalarValued where Self: BinaryOperator { 16 | static var inputValueKinds: [Value.Kind] { return [.scalar, .scalar] } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Anomalii/General.swift: -------------------------------------------------------------------------------- 1 | // 2 | // General.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 16/12/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | func repeatedlyAttemptToCreate(maximumAttempts: Int = 10, makingWith creationBlock: ()->T?) -> T? { 11 | var attempts = 0 12 | var result: T? 13 | while result == nil && attempts < maximumAttempts { 14 | attempts += 1 15 | result = creationBlock() 16 | } 17 | return result 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Anomalii/VectorValued.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vector.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 10/12/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol VectorValued: Expression { 11 | } 12 | 13 | extension VectorValued { 14 | public static var outputValueKind: Value.Kind { return .vector } 15 | } 16 | 17 | extension VectorValued where Self: BinaryOperator { 18 | static var inputValueKinds: [Value.Kind] { return [.vector, .vector] } 19 | } 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Anomalii", 7 | products: [ 8 | .library( 9 | name: "Anomalii", 10 | targets: ["Anomalii"]), 11 | ], 12 | dependencies: [ 13 | ], 14 | targets: [ 15 | .target( 16 | name: "Anomalii", 17 | dependencies: []), 18 | .testTarget( 19 | name: "AnomaliiTests", 20 | dependencies: ["Anomalii"]), 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/Anomalii_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/AnomaliiTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/PopulatorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopulatorTests.swift 3 | // AnomaliiTests 4 | // 5 | // Created by Drew McCormack on 26/11/2017. 6 | // 7 | 8 | import XCTest 9 | @testable import Anomalii 10 | 11 | class PopulatorTests: XCTestCase { 12 | 13 | var populator: Populator! 14 | 15 | override func setUp() { 16 | super.setUp() 17 | let metrics = Populator.Metrics(populationSize: 10, maximumDepth: 5) 18 | var components = PopulationComponents() 19 | components.variables = [ScalarVariable(named: "x")] 20 | populator = Populator(withMetrics: metrics, components: components) 21 | } 22 | 23 | func testDepth() { 24 | let p = populator.makePopulation() 25 | XCTAssertEqual(p.filter({ $0.depth != 5 }).count, 0) 26 | } 27 | 28 | func testSize() { 29 | XCTAssertEqual(populator.makePopulation().count, 10) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Anomalii/Terminal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Terminal.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | public protocol Terminal: Expression { 12 | } 13 | 14 | public extension Terminal { 15 | public static var arity: Int { return 0 } 16 | public var isValid: Bool { return true } 17 | public var depth: Int { return 1 } 18 | 19 | public func traverse(executingForEach visiter: (Expression)->Void) { 20 | visiter(self) 21 | } 22 | 23 | public func traverse(where condition: ((Expression)->Bool)? = nil, visitWith visiter: (Expression) -> Void) { 24 | if (condition?(self) ?? true) { visiter(self) } 25 | } 26 | 27 | public func transformed(where condition: ((Expression)->Bool)? = nil, by transformer: (Expression)->Expression) -> Expression { 28 | return (condition?(self) ?? true) ? transformer(self) : self 29 | } 30 | 31 | public func count(where condition: ((Expression) -> Bool)?) -> Int { 32 | return condition?(self) ?? false ? 1 : 0 33 | } 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 The Mental Faculty B.V. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/CodableTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodableTests.swift 3 | // AnomaliiTests 4 | // 5 | // Created by Drew McCormack on 24/11/2017. 6 | // 7 | 8 | import XCTest 9 | @testable import Anomalii 10 | 11 | class CodableTests: XCTestCase { 12 | 13 | var expression: ScalarAddition! 14 | let jsonEncoder = JSONEncoder() 15 | let jsonDecoder = JSONDecoder() 16 | 17 | override func setUp() { 18 | super.setUp() 19 | expressionTypes = [ScalarAddition.self, ScalarMultiplication.self, ScalarConstant.self, ScalarVariable.self] 20 | expression = ScalarAddition(withChildren: [ScalarConstant(doubleValue: 10), ScalarConstant(doubleValue: 5)]) 21 | } 22 | 23 | func testEncodeAndDecode() { 24 | let data = try! jsonEncoder.encode(expression) 25 | let newExpression = try! jsonDecoder.decode(ScalarAddition.self, from: data) 26 | XCTAssert(expression.isSame(as: newExpression)) 27 | } 28 | 29 | func testAnyExpressionEncodeAndDecode() { 30 | let data = try! jsonEncoder.encode(AnyExpression(expression)) 31 | let any = try! jsonDecoder.decode(AnyExpression.self, from: data) 32 | XCTAssert(expression.isSame(as: any.expression)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Anomalii/Random.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Random.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension Double { 11 | public static var random: Double { 12 | return Double(arc4random()) / Double(UInt32.max) 13 | } 14 | } 15 | 16 | public extension ClosedRange where Bound == Int { 17 | public var random: Int { 18 | return lowerBound + Int(arc4random() % UInt32(count)) 19 | } 20 | } 21 | 22 | public extension ClosedRange where Bound == Double { 23 | public var random: Double { 24 | return lowerBound + Double.random * (upperBound-lowerBound) 25 | } 26 | } 27 | 28 | public extension Array { 29 | public var random: Element? { 30 | guard count > 0 else { return nil } 31 | return self[(0...count-1).random] 32 | } 33 | 34 | public func random(choosing numberElements: Int) -> [Element] { 35 | guard numberElements < count else { return self } 36 | var indexes = Set() 37 | while indexes.count < numberElements { 38 | let random: Int = (0...count-1).random 39 | indexes.insert(random) 40 | } 41 | return indexes.map { self[$0] } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Sources/Anomalii/Populator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Populator.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public class Populator { 11 | 12 | public struct Metrics { 13 | public var populationSize: Int 14 | public var maximumDepth: Int 15 | 16 | public init(populationSize: Int = 500, maximumDepth: Int = 10) { 17 | self.populationSize = populationSize 18 | self.maximumDepth = maximumDepth 19 | } 20 | } 21 | 22 | public let metrics: Metrics 23 | public let components: PopulationComponents 24 | private let orator: Orator 25 | 26 | public init(withMetrics metrics: Metrics, components: PopulationComponents) { 27 | self.metrics = metrics 28 | self.components = components 29 | self.orator = Orator(withComponents: components, maximumDepth: metrics.maximumDepth) 30 | } 31 | 32 | public func makePopulation() -> [Expression] { 33 | var population = [Expression]() 34 | while population.count < metrics.populationSize { 35 | guard let expression = orator.expression(withOutputValueKind: components.memberValueKind) else { continue } 36 | population.append(expression) 37 | } 38 | return population 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/OratorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OratorTests.swift 3 | // AnomaliiTests 4 | // 5 | // Created by Drew McCormack on 25/11/2017. 6 | // 7 | 8 | import XCTest 9 | @testable import Anomalii 10 | 11 | class OratorTests: XCTestCase { 12 | 13 | var orator: Orator! 14 | 15 | override func setUp() { 16 | super.setUp() 17 | var components = PopulationComponents() 18 | components.variables = [ScalarVariable(named: "x"), VectorVariable(named: "y")] 19 | components.constantTypes += [VectorConstant.self] 20 | components.operatorTypes += [DotProduct.self, VectorAddition.self, ScalarVectorMultiplication.self] as! [Operator.Type] 21 | orator = Orator(withComponents: components, maximumDepth: 5) 22 | } 23 | 24 | func testOration() { 25 | let expression = orator.expression(withOutputValueKind: .scalar) 26 | XCTAssertNotNil(expression) 27 | XCTAssertEqual(expression!.depth, 5) 28 | } 29 | 30 | func testValidity() { 31 | for _ in 0..<10 { 32 | let expression = orator.expression(withOutputValueKind: .scalar) 33 | XCTAssertTrue(expression?.isValid ?? false) 34 | 35 | let vectorExpression = orator.expression(withOutputValueKind: .vector) 36 | XCTAssertTrue(vectorExpression?.isValid ?? false) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Anomalii/Traversal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Traversal.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 16/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | struct TraversalIndex { 11 | var index: Int 12 | var visitCondition: ((Expression)->Bool)? 13 | 14 | init(index: Int, visitCondition: ((Expression)->Bool)? = nil) { 15 | self.index = index 16 | self.visitCondition = visitCondition 17 | } 18 | } 19 | 20 | extension Expression { 21 | 22 | public func count(where condition: ((Expression)->Bool)?) -> Int { 23 | var numberNodes = 0 24 | traverse(where: condition) { _ in numberNodes += 1 } 25 | return numberNodes 26 | } 27 | 28 | func expression(at traversalIndex: TraversalIndex) -> Expression { 29 | var index = 0 30 | var result: Expression? 31 | traverse(where: traversalIndex.visitCondition) { 32 | if index == traversalIndex.index { result = $0 } 33 | index += 1 34 | } 35 | return result! 36 | } 37 | 38 | func expression(substituting substitute: Expression, at traversalIndex: TraversalIndex) -> Expression { 39 | var index = 0 40 | return transformed(where: traversalIndex.visitCondition) { 41 | let node = index == traversalIndex.index ? substitute : $0 42 | index += 1 43 | return node 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Anomalii 2 | 3 | _Author:_ Drew McCormack
4 | _Last Updated:_ 1 December, 2017 5 | 6 | An exploratory Swift framework for Genetic Programming. 7 | 8 | ## What is Genetic Programming? 9 | 10 | A branch of machine learning in which simple programs or mathematical functions compete to solve a problem, evolving along the lines of Darwinian evolution. A population of solutions can cross pollinate and mutate, and so evolve through generations to 'fitter' descendants. 11 | 12 | For a detailed overview, see [A Field Guide to Genetic Programming](http://www.gp-field-guide.org.uk). 13 | 14 | ## What Works? 15 | 16 | - Simple scalar mathematical expressions, comprised of basic operators like addition and multiplication, decimal constants, and variables 17 | - Mathematical expressions are trees of value types (structs) 18 | - The basic elements of the Genetic Programming (GP), namely initial population generation, evolutionary operators including crossover and mutation 19 | - Storing of populations and expressions using the Swift `Codable` protocol 20 | - Basic unit tests 21 | - A basic regression test showing how a function can be fitted by genetic programming 22 | 23 | ## What is Lacking? 24 | 25 | - There are few mathematical operators at this point, though they are very easy to add. Useful would be division and trigonometic functions 26 | - The plan is to support vector expressions, and perhaps even matrices 27 | 28 | ## How to Install 29 | 30 | Anomalii can be installed with the Swift Package Manager, or by building the framework target in Xcode. 31 | -------------------------------------------------------------------------------- /Sources/Anomalii/ScalarOperator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScalarOperator.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | public struct ScalarAddition: BinaryOperator, ScalarValued { 9 | public var children: [Expression] 10 | 11 | public init(withChildren children: [Expression]) { 12 | self.children = children 13 | } 14 | 15 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 16 | let first = children[0].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 17 | let second = children[1].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 18 | return first + second 19 | } 20 | 21 | public var description: String { 22 | return "(\(children.first!) + \(children.last!))" 23 | } 24 | } 25 | 26 | public struct ScalarMultiplication: BinaryOperator, ScalarValued { 27 | public var children: [Expression] 28 | 29 | public init(withChildren children: [Expression]) { 30 | self.children = children 31 | } 32 | 33 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 34 | let first = children[0].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 35 | let second = children[1].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 36 | return first * second 37 | } 38 | 39 | public var description: String { 40 | return "(\(children.first!) * \(children.last!))" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/RegressionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegressionTests.swift 3 | // AnomaliiTests 4 | // 5 | // Created by Drew McCormack on 30/11/2017. 6 | // 7 | 8 | import XCTest 9 | import Anomalii 10 | 11 | class RegressionTests: XCTestCase, FitnessEvaluator { 12 | 13 | var x: [Double]! 14 | var y: [Double]! 15 | 16 | var solver: Solver! 17 | var parameters = EvaluationParameters() 18 | 19 | override func setUp() { 20 | super.setUp() 21 | x = (-5...5).map { Double($0) } 22 | y = x.map { $0*$0 + $0 + Double.random } 23 | var config = Solver.Configuration() 24 | config.populationMetrics.maximumDepth = 8 25 | config.populationMetrics.populationSize = 50 26 | solver = Solver(configuration: config, fitnessEvaluator: self) 27 | } 28 | 29 | func testEvolution() { 30 | solver.evolve(generations: 100) 31 | let winner = solver.bestCandidate 32 | let values = x.map { winner.evaluated(forVariableValuesByName: ["x":Value.scalar($0)], parameters: parameters) } 33 | for case let (yValue, .scalar(winnerY)) in zip(y, values) { 34 | XCTAssertEqual(winnerY, yValue, accuracy: 2.0) 35 | } 36 | } 37 | 38 | func fitness(of expression: Expression) -> Double { 39 | let sumOfErrorSquares = zip(x,y).reduce(0.0) { (sum, xy) in 40 | let (x,y) = xy 41 | if case let .scalar(expressionY) = expression.evaluated(forVariableValuesByName: ["x":.scalar(x)], parameters: parameters) { 42 | let diff = y - expressionY 43 | return sum + diff * diff 44 | } else { 45 | fatalError() 46 | } 47 | } 48 | return 1.0 / max(1.0e-8, sumOfErrorSquares) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Anomalii/Value.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Value.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | public enum Value { 9 | case scalar(Double) 10 | case vector([Double]) 11 | 12 | public enum Kind { 13 | case scalar 14 | case vector 15 | } 16 | 17 | public var kind: Value.Kind { 18 | switch self { 19 | case .scalar: 20 | return .scalar 21 | case .vector: 22 | return .vector 23 | } 24 | } 25 | 26 | static func +(left: Value, right: Value) -> Value { 27 | switch (left, right) { 28 | case let (.scalar(l), .scalar(r)): 29 | return .scalar(l+r) 30 | case let (.vector(l), .vector(r)): 31 | return .vector(zip(l, r).map({ (l,r) in l+r })) 32 | case (.scalar, .vector), (.vector, .scalar): 33 | fatalError() 34 | } 35 | } 36 | 37 | static func *(left: Value, right: Value) -> Value { 38 | switch (left, right) { 39 | case let (.scalar(l), .scalar(r)): 40 | return .scalar(l*r) 41 | case let (.vector(l), .vector(r)): 42 | return .vector(zip(l, r).map({ (l,r) in l*r })) 43 | case let (.scalar(s), .vector(v)): 44 | return .vector(v.map({ $0 * s })) 45 | case let (.vector(v), .scalar(s)): 46 | return .vector(v.map({ $0 * s })) 47 | } 48 | } 49 | 50 | static func dotProduct(_ left: Value, _ right: Value) -> Value { 51 | switch (left, right) { 52 | case let (.vector(l), .vector(r)): 53 | return .scalar(zip(l, r).reduce(0.0, { (sum, pair) in sum + pair.0*pair.1 })) 54 | case (.scalar, .scalar), (.scalar, .vector), (.vector, .scalar): 55 | fatalError() 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/StandardMutatorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StandardMutatorTests.swift 3 | // AnomaliiTests 4 | // 5 | // Created by Drew McCormack on 26/11/2017. 6 | // 7 | 8 | import XCTest 9 | @testable import Anomalii 10 | 11 | class StandardMutatorTests: XCTestCase { 12 | 13 | var mutator: StandardMutator! 14 | var e1, e2: Expression! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | 19 | var components = PopulationComponents() 20 | components.variables = [ScalarVariable(named: "x"), VectorVariable(named: "y")] 21 | components.constantTypes += [VectorConstant.self] 22 | components.operatorTypes += [DotProduct.self, VectorAddition.self, ScalarVectorMultiplication.self] as! [Operator.Type] 23 | mutator = StandardMutator(populationComponents: components) 24 | 25 | let sub1 = ScalarAddition(withChildren: [ScalarConstant(doubleValue: 10), ScalarConstant(doubleValue: 5)]) 26 | e1 = ScalarAddition(withChildren: [sub1, ScalarConstant(doubleValue: 4)]) 27 | e2 = ScalarAddition(withChildren: [DotProduct(withChildren: [VectorVariable(named: "y"), VectorConstant(elementValue: 1.0)]), ScalarConstant(doubleValue: 3)]) 28 | } 29 | 30 | func testCrossing() { 31 | var noCrossing = true 32 | for _ in 0..<10 { 33 | let crossed = mutator.expression(crossing: e1, with: e2)! 34 | noCrossing = noCrossing && (e1.isSame(as: crossed) || e2.isSame(as: crossed)) 35 | XCTAssertTrue(crossed.isValid) 36 | } 37 | XCTAssertFalse(noCrossing) 38 | } 39 | 40 | func testMutating() { 41 | for _ in 0..<10 { 42 | let mutated = mutator.expression(mutating: e1)! 43 | XCTAssertLessThanOrEqual(mutated.depth, 6) 44 | XCTAssertFalse(e1.isSame(as: mutated)) 45 | XCTAssertTrue(mutated.isValid) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/Anomalii/Solver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Solver.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct PopulationComponents { 11 | public var operatorTypes: [Operator.Type] = [ScalarAddition.self, ScalarMultiplication.self] 12 | public var constantTypes: [Constant.Type] = [ScalarConstant.self] 13 | public var variables: [Variable] = [ScalarVariable(named: "x")] 14 | public var memberValueKind: Value.Kind = .scalar 15 | public var constantRange: ClosedRange = -10...10 16 | public init() {} 17 | } 18 | 19 | public class Solver { 20 | public struct Configuration { 21 | public var populationComponents: PopulationComponents = PopulationComponents() 22 | public var populationMetrics = Populator.Metrics() 23 | public init() {} 24 | } 25 | 26 | public let configuration: Configuration 27 | public let fitnessEvaluator: FitnessEvaluator 28 | public let initialPopulation: [Expression] 29 | 30 | public var population: [Expression] { return evolver.population } 31 | public var bestCandidate: Expression { 32 | return evolver.fitnessResults().max(by: { $0.fitness < $1.fitness })!.expression 33 | } 34 | 35 | private let populator: Populator 36 | private let mutator: StandardMutator 37 | private let evolver: Evolver 38 | 39 | public init(configuration: Configuration, fitnessEvaluator: FitnessEvaluator) { 40 | self.configuration = configuration 41 | self.fitnessEvaluator = fitnessEvaluator 42 | self.mutator = StandardMutator(populationComponents: configuration.populationComponents) 43 | self.populator = Populator(withMetrics: configuration.populationMetrics, components: configuration.populationComponents) 44 | self.initialPopulation = populator.makePopulation() 45 | self.evolver = Evolver(initialPopulation: initialPopulation, evaluatingFitnessWith: fitnessEvaluator, mutatingWith: mutator) 46 | } 47 | 48 | public func evolve(generations: Int) { 49 | (0.. Expression? { 22 | var e: Expression? 23 | currentDepth += 1 24 | defer { currentDepth -= 1 } 25 | if currentDepth < maximumDepth { 26 | let candidates = components.operatorTypes.filter { outputKind == $0.outputValueKind } 27 | guard let op = candidates.random else { return nil } 28 | let children = op.inputValueKinds.flatMap { 29 | expression(withOutputValueKind: $0) 30 | } 31 | guard children.count == op.inputValueKinds.count else { return nil } 32 | e = op.init(withChildren: children) 33 | } else { 34 | e = repeatedlyAttemptToCreate() { 35 | switch (0...1).random { 36 | case 0: 37 | let candidates = components.constantTypes.filter { outputKind == $0.outputValueKind } 38 | let constantType = candidates.random 39 | switch constantType { 40 | case is ScalarConstant.Type: 41 | return ScalarConstant(randomWithValuesIn: components.constantRange) 42 | case is VectorConstant.Type: 43 | return VectorConstant(randomWithValuesIn: components.constantRange) 44 | default: 45 | fatalError() 46 | } 47 | case 1: 48 | let candidates = components.variables.filter { outputKind == type(of: $0).outputValueKind } 49 | return candidates.random 50 | default: 51 | fatalError() 52 | } 53 | } 54 | } 55 | return e 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Anomalii/Expression.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Expression.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | public struct EvaluationParameters { 9 | public var vectorLength: Int = 1 10 | public init() {} 11 | } 12 | 13 | public protocol Expression: Codable, CustomStringConvertible { 14 | static var codingKey: String { get } 15 | static var outputValueKind: Value.Kind { get } 16 | static var arity: Int { get } 17 | var isValid: Bool { get } 18 | var depth: Int { get } 19 | func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value 20 | func transformed(where condition: ((Expression)->Bool)?, by transformer: (Expression)->Expression) -> Expression 21 | func traverse(where condition: ((Expression)->Bool)?, visitWith visiter: (Expression)->Void) 22 | func count(where condition: ((Expression)->Bool)?) -> Int 23 | func isSame(as other: Expression) -> Bool 24 | } 25 | 26 | public extension Expression { 27 | static var codingKey: String { 28 | return String(describing: self) 29 | } 30 | } 31 | 32 | internal struct AnyExpression: Codable { 33 | var expression: Expression 34 | 35 | init(_ expression: Expression) { 36 | self.expression = expression 37 | } 38 | 39 | private enum Key: CodingKey { 40 | case type, expression 41 | } 42 | 43 | init(from decoder: Decoder) throws { 44 | let container = try decoder.container(keyedBy: Key.self) 45 | let typeKey = try container.decode(String.self, forKey: .type) 46 | let type = expressionTypesByCodingKey[typeKey]! 47 | self.expression = try type.init(from: container.superDecoder(forKey: .expression)) 48 | } 49 | 50 | func encode(to encoder: Encoder) throws { 51 | var container = encoder.container(keyedBy: Key.self) 52 | try container.encode(type(of: expression).codingKey, forKey: .type) 53 | try expression.encode(to: container.superEncoder(forKey: .expression)) 54 | } 55 | } 56 | 57 | 58 | public var expressionTypes: [Expression.Type] = [] { 59 | didSet { 60 | expressionTypesByCodingKey = expressionTypes.reduce([:]) { result, type in 61 | var newResult = result 62 | newResult[type.codingKey] = type 63 | return newResult 64 | } 65 | } 66 | } 67 | 68 | public var expressionTypesByCodingKey: [String:Expression.Type] = [:] 69 | -------------------------------------------------------------------------------- /Sources/Anomalii/Operator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Operator.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | enum OperatorCodingKey: String, CodingKey { 9 | case children 10 | } 11 | 12 | public protocol Operator: Expression { 13 | static var inputValueKinds: [Value.Kind] { get } 14 | var children: [Expression] { get set } 15 | init(withChildren children: [Expression]) 16 | } 17 | 18 | public extension Operator { 19 | public static var arity: Int { return inputValueKinds.count } 20 | 21 | var depth: Int { 22 | return 1 + children.reduce(0) { max($1.depth, $0) } 23 | } 24 | 25 | init(from decoder: Decoder) throws { 26 | self.init(withChildren: []) 27 | let values = try decoder.container(keyedBy: OperatorCodingKey.self) 28 | let anyChildren = try values.decode([AnyExpression].self, forKey: .children) 29 | children = anyChildren.map { $0.expression } 30 | } 31 | 32 | func encode(to encoder: Encoder) throws { 33 | var container = encoder.container(keyedBy: OperatorCodingKey.self) 34 | let anyChildren = children.map { AnyExpression($0) } 35 | try container.encode(anyChildren, forKey: .children) 36 | } 37 | 38 | func traverse(where condition: ((Expression)->Bool)? = nil, visitWith visiter: (Expression)->Void) { 39 | children.forEach { $0.traverse(where: condition, visitWith: visiter) } 40 | if (condition?(self) ?? true) { visiter(self) } 41 | } 42 | 43 | func transformed(where condition: ((Expression)->Bool)? = nil, by transformer: (Expression)->Expression) -> Expression { 44 | var newSelf = self 45 | let newChildren = children.map { $0.transformed(where: condition, by: transformer) } 46 | newSelf.children = newChildren 47 | return (condition?(self) ?? true) ? transformer(newSelf) : newSelf 48 | } 49 | 50 | var isValid: Bool { 51 | return children.enumerated().reduce(true) { result, indexChild in 52 | return result && type(of: indexChild.1).outputValueKind == Self.inputValueKinds[indexChild.0] 53 | } 54 | } 55 | 56 | func isSame(as other: Expression) -> Bool { 57 | guard let otherOperator = other as? Self else { return false } 58 | return zip(children, otherOperator.children).reduce(true) { (result, pair) in 59 | return result && pair.0.isSame(as: pair.1) 60 | } 61 | } 62 | } 63 | 64 | public protocol BinaryOperator: Operator { 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Anomalii/Variable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Variable.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 10/12/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol Variable: Terminal { 11 | var name: String { get } 12 | } 13 | 14 | public struct ScalarVariable: Variable, ScalarValued { 15 | public let name: String 16 | public static let outputValueKind: Value.Kind = .scalar 17 | 18 | public init(named name: String) { 19 | self.name = name 20 | } 21 | 22 | private enum Key: String, CodingKey { 23 | case name 24 | } 25 | 26 | public init(from decoder: Decoder) throws { 27 | let values = try decoder.container(keyedBy: Key.self) 28 | name = try values.decode(String.self, forKey: .name) 29 | } 30 | 31 | public func encode(to encoder: Encoder) throws { 32 | var container = encoder.container(keyedBy: Key.self) 33 | try container.encode(name, forKey: .name) 34 | } 35 | 36 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 37 | return valuesByName[name]! 38 | } 39 | 40 | public func isSame(as other: Expression) -> Bool { 41 | guard let otherVariable = other as? Variable else { return false } 42 | return name == otherVariable.name 43 | } 44 | 45 | public var description: String { 46 | return "\(name)" 47 | } 48 | } 49 | 50 | public struct VectorVariable: Variable, VectorValued { 51 | public let name: String 52 | public static let outputValueKind: Value.Kind = .vector 53 | 54 | public init(named name: String) { 55 | self.name = name 56 | } 57 | 58 | private enum Key: String, CodingKey { 59 | case name 60 | } 61 | 62 | public init(from decoder: Decoder) throws { 63 | let values = try decoder.container(keyedBy: Key.self) 64 | name = try values.decode(String.self, forKey: .name) 65 | } 66 | 67 | public func encode(to encoder: Encoder) throws { 68 | var container = encoder.container(keyedBy: Key.self) 69 | try container.encode(name, forKey: .name) 70 | } 71 | 72 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 73 | return valuesByName[name]! 74 | } 75 | 76 | public func isSame(as other: Expression) -> Bool { 77 | guard let otherVariable = other as? Variable else { return false } 78 | return name == otherVariable.name 79 | } 80 | 81 | public var description: String { 82 | return "\(name)" 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /Sources/Anomalii/VectorOperator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VectorOperator.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 05/12/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct VectorAddition: BinaryOperator { 11 | public static var inputValueKinds: [Value.Kind] { return [.vector, .vector] } 12 | public static var outputValueKind: Value.Kind { return .vector } 13 | public var children: [Expression] 14 | 15 | public init(withChildren children: [Expression]) { 16 | self.children = children 17 | } 18 | 19 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 20 | let first = children[0].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 21 | let second = children[1].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 22 | return first + second 23 | } 24 | 25 | public var description: String { 26 | return "(\(children.first!) + \(children.last!))" 27 | } 28 | } 29 | 30 | public struct ScalarVectorMultiplication: BinaryOperator { 31 | public static var inputValueKinds: [Value.Kind] { return [.scalar, .vector] } 32 | public static var outputValueKind: Value.Kind { return .vector } 33 | public var children: [Expression] 34 | 35 | public init(withChildren children: [Expression]) { 36 | self.children = children 37 | } 38 | 39 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 40 | let first = children[0].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 41 | let second = children[1].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 42 | return first * second 43 | } 44 | 45 | public var description: String { 46 | return "(\(children.first!) * \(children.last!))" 47 | } 48 | } 49 | 50 | public struct DotProduct: BinaryOperator { 51 | public static var inputValueKinds: [Value.Kind] { return [.vector, .vector] } 52 | public static var outputValueKind: Value.Kind { return .scalar } 53 | public var children: [Expression] 54 | 55 | public init(withChildren children: [Expression]) { 56 | self.children = children 57 | } 58 | 59 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 60 | let first = children[0].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 61 | let second = children[1].evaluated(forVariableValuesByName: valuesByName, parameters: parameters) 62 | return Value.dotProduct(first, second) 63 | } 64 | 65 | public var description: String { 66 | return "(\(children.first!) . \(children.last!))" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Sources/Anomalii/Mutator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mutator.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | protocol Mutator: class { 9 | func expression(mutating expression: Expression) -> Expression? 10 | func expression(crossing expression1: Expression, with expression2: Expression) -> Expression? 11 | } 12 | 13 | class StandardMutator: Mutator { 14 | let components: PopulationComponents 15 | 16 | init(populationComponents: PopulationComponents) { 17 | self.components = populationComponents 18 | } 19 | 20 | func expression(mutating expression: Expression) -> Expression? { 21 | // Implement as a cross with a random expression 22 | let orator = Orator(withComponents: components, maximumDepth: expression.depth) 23 | guard let other = orator.expression(withOutputValueKind: components.memberValueKind) else { return nil } 24 | return self.expression(crossing: expression, with: other) 25 | } 26 | 27 | func expression(crossing expression1: Expression, with expression2: Expression) -> Expression? { 28 | return repeatedlyAttemptToCreate { 29 | // Choose first subtree 30 | guard let indexToCross1 = randomTraversalIndex(in: expression1) else { return nil } 31 | 32 | // Try to get a second subtree of the same kind 33 | let subExpression1 = expression1.expression(at: indexToCross1) 34 | let kind = type(of: subExpression1).outputValueKind 35 | guard let indexToCross2 = randomTraversalIndex(in: expression2, forOutputKind: kind) else { return nil } 36 | 37 | // Substitute the node 38 | let subExpression2 = expression2.expression(at: indexToCross2) 39 | return expression1.expression(substituting: subExpression2, at: indexToCross1) 40 | } 41 | } 42 | 43 | private func randomTraversalIndex(in expression: Expression, forOutputKind outputKind: Value.Kind? = nil) -> TraversalIndex? { 44 | return repeatedlyAttemptToCreate { 45 | let mutateLeaf = (0.0...1.0).random > 0.9 // 10% leaf mutation 46 | func isValidType(expression: Expression) -> Bool { 47 | guard 48 | outputKind == nil || 49 | outputKind == type(of: expression).outputValueKind else { 50 | return false 51 | } 52 | if mutateLeaf { 53 | return expression is Terminal 54 | } else { 55 | return expression is Operator 56 | } 57 | } 58 | 59 | let nodeCount = expression.count(where: isValidType) 60 | if nodeCount < 1 { return nil } 61 | return TraversalIndex(index:(0...nodeCount-1).random, visitCondition: isValidType) 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Anomalii/Constant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constant.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 10/12/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol Constant: Terminal { 11 | } 12 | 13 | public struct ScalarConstant: Constant, ScalarValued { 14 | let doubleValue: Double 15 | 16 | init(doubleValue: Double) { 17 | self.doubleValue = doubleValue 18 | } 19 | 20 | init(randomWithValuesIn range: ClosedRange) { 21 | self.doubleValue = range.random 22 | } 23 | 24 | enum Key: String, CodingKey { 25 | case doubleValue 26 | } 27 | 28 | public init(from decoder: Decoder) throws { 29 | let values = try decoder.container(keyedBy: Key.self) 30 | doubleValue = try values.decode(Double.self, forKey: .doubleValue) 31 | } 32 | 33 | public func encode(to encoder: Encoder) throws { 34 | var container = encoder.container(keyedBy: Key.self) 35 | try container.encode(doubleValue, forKey: .doubleValue) 36 | } 37 | 38 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 39 | return .scalar(doubleValue) 40 | } 41 | 42 | public func isSame(as other: Expression) -> Bool { 43 | guard let otherConstant = other as? ScalarConstant else { return false } 44 | return doubleValue == otherConstant.doubleValue 45 | } 46 | 47 | public var description: String { 48 | return "\(doubleValue)" 49 | } 50 | } 51 | 52 | public struct VectorConstant: Constant, VectorValued { 53 | let elementValue: Double 54 | 55 | init(elementValue: Double) { 56 | self.elementValue = elementValue 57 | } 58 | 59 | public init(randomWithValuesIn range: ClosedRange) { 60 | self.elementValue = range.random 61 | } 62 | 63 | enum Key: String, CodingKey { 64 | case elementValue 65 | } 66 | 67 | public init(from decoder: Decoder) throws { 68 | let values = try decoder.container(keyedBy: Key.self) 69 | elementValue = try values.decode(Double.self, forKey: .elementValue) 70 | } 71 | 72 | public func encode(to encoder: Encoder) throws { 73 | var container = encoder.container(keyedBy: Key.self) 74 | try container.encode(elementValue, forKey: .elementValue) 75 | } 76 | 77 | public func evaluated(forVariableValuesByName valuesByName: [String:Value], parameters: EvaluationParameters) -> Value { 78 | let vectorValue = [Double](repeating: elementValue, count: parameters.vectorLength) 79 | return .vector(vectorValue) 80 | } 81 | 82 | public func isSame(as other: Expression) -> Bool { 83 | guard let otherConstant = other as? VectorConstant else { return false } 84 | return elementValue == otherConstant.elementValue 85 | } 86 | 87 | public var description: String { 88 | return "[\(elementValue)]" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/ExpressionTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Anomalii 3 | 4 | class ExpressionTests: XCTestCase { 5 | 6 | var expression: Expression! 7 | let parameters = EvaluationParameters() 8 | 9 | override func setUp() { 10 | super.setUp() 11 | expression = ScalarAddition(withChildren: [ScalarConstant(doubleValue: 10), ScalarConstant(doubleValue: 5)]) 12 | } 13 | 14 | override func tearDown() { 15 | super.tearDown() 16 | } 17 | 18 | func testCount() { 19 | XCTAssertEqual(expression.count(where: nil), 3) 20 | } 21 | 22 | func testCountWithCondition() { 23 | XCTAssertEqual(expression.count(where: { $0 is Terminal }), 2) 24 | } 25 | 26 | func testDepth() { 27 | XCTAssertEqual(expression.depth, 2) 28 | } 29 | 30 | func testEvaluation() { 31 | guard case let .scalar(value) = expression.evaluated(forVariableValuesByName: [:], parameters: parameters) else { XCTFail(); return } 32 | XCTAssertEqual(value, 15.0) 33 | } 34 | 35 | func testEvaluationWithVariable() { 36 | let e = ScalarAddition(withChildren: [ScalarVariable(named: "tom"), ScalarConstant(doubleValue: 5)]) 37 | guard case let .scalar(value) = e.evaluated(forVariableValuesByName: ["tom":.scalar(-2)], parameters: parameters) else { XCTFail(); return } 38 | XCTAssertEqual(value, 3.0) 39 | } 40 | 41 | func testSameness() { 42 | let otherExpression = ScalarAddition(withChildren: [ScalarConstant(doubleValue: 5), ScalarConstant(doubleValue: 5)]) 43 | XCTAssertTrue(ScalarConstant(doubleValue: 5.0).isSame(as: ScalarConstant(doubleValue: 5.0))) 44 | XCTAssertTrue(expression.isSame(as: expression)) 45 | XCTAssertFalse(expression.isSame(as: otherExpression)) 46 | XCTAssertFalse(ScalarConstant(doubleValue: -5.0).isSame(as: ScalarConstant(doubleValue: 5.0))) 47 | XCTAssertFalse(ScalarVariable(named: "blah").isSame(as: ScalarConstant(doubleValue: 5.0))) 48 | XCTAssertTrue(ScalarVariable(named: "blah").isSame(as: ScalarVariable(named: "blah"))) 49 | XCTAssertFalse(ScalarVariable(named: "blah").isSame(as: ScalarVariable(named: "ball"))) 50 | XCTAssertFalse(expression.isSame(as: ScalarConstant(doubleValue: 5.0))) 51 | } 52 | 53 | func testExtraction() { 54 | let firstChild = expression.expression(at: TraversalIndex(index: 0)) 55 | let secondChild = expression.expression(at: TraversalIndex(index: 1)) 56 | let root = expression.expression(at: TraversalIndex(index: 2)) 57 | XCTAssertTrue(expression.isSame(as: root)) 58 | XCTAssertTrue(ScalarConstant(doubleValue: 10).isSame(as: firstChild)) 59 | XCTAssertTrue(ScalarConstant(doubleValue: 5).isSame(as: secondChild)) 60 | } 61 | 62 | func testSubstitution() { 63 | let substituted = expression.expression(substituting: ScalarVariable(named: "bob"), at: TraversalIndex(index: 0)) 64 | let result = ScalarAddition(withChildren: [ScalarVariable(named: "bob"), ScalarConstant(doubleValue: 5)]) 65 | XCTAssertTrue(substituted.isSame(as: result)) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Tests/AnomaliiTests/MultidimensionalOptimizationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultidimensionalOptimizationTests.swift 3 | // AnomaliiTests 4 | // 5 | // Attempts to create an optimizer trained on Rosenbrock function, which is 6 | // notoriously difficult to optimize. https://en.wikipedia.org/wiki/Rosenbrock_function 7 | // 8 | // Created by Drew McCormack on 15/12/2017. 9 | // 10 | 11 | import XCTest 12 | import Anomalii 13 | 14 | class MultidimensionalOptimizationTests: XCTestCase, FitnessEvaluator { 15 | 16 | var startingPoints: [[Double]]! 17 | var solver: Solver! 18 | var parameters = EvaluationParameters() 19 | 20 | override func setUp() { 21 | super.setUp() 22 | 23 | parameters.vectorLength = 2 24 | 25 | startingPoints = [[Double]]() 26 | for _ in 0..<20 { 27 | let point = [(-1.0...1.0).random, (-1.0...1.0).random] 28 | startingPoints.append(point) 29 | } 30 | 31 | var config = Solver.Configuration() 32 | config.populationComponents.constantTypes = [ScalarConstant.self, VectorConstant.self] 33 | config.populationComponents.variables = [VectorVariable(named: "grad")] 34 | config.populationComponents.memberValueKind = .vector 35 | config.populationComponents.operatorTypes = [DotProduct.self, VectorAddition.self, ScalarVectorMultiplication.self, ScalarAddition.self, ScalarMultiplication.self] 36 | config.populationMetrics.maximumDepth = 8 37 | config.populationMetrics.populationSize = 50 38 | 39 | solver = Solver(configuration: config, fitnessEvaluator: self) 40 | } 41 | // 42 | // func testEvolution() { 43 | // solver.evolve(generations: 100) 44 | //// let winner = solver.bestCandidate 45 | //// let values = x.map { winner.evaluated(for: ["x":Value.vector($0)]) } 46 | //// for case let (yValue, .scalar(winnerY)) in zip(y, values) { 47 | //// XCTAssertEqual(winnerY, yValue, accuracy: 2.0) 48 | //// } 49 | // } 50 | 51 | func fitness(of expression: Expression) -> Double { 52 | let sumOfErrorSquares = startingPoints.reduce(0.0) { (sum, point) in 53 | if case let .vector(step) = expression.evaluated(forVariableValuesByName: ["x":.vector(point)], parameters: parameters) { 54 | let targetStep = point.map { -$0 } // Minimum is at (0,0) 55 | let part = zip(step, targetStep).reduce(0.0) { sum, pair in 56 | let diff = (pair.0 - pair.1) 57 | return sum + diff * diff 58 | } 59 | return sum + part 60 | } else { 61 | fatalError() 62 | } 63 | } 64 | return 1.0 / max(1.0e-8, sumOfErrorSquares) 65 | } 66 | 67 | /// Function is (a-x1)^2+b(x2-x1^2)^2 68 | /// The minimum is at (1,1) 69 | func rosenbrock(_ x: [Double]) -> Double { 70 | precondition(x.count == 2) 71 | let a = 1.0 72 | let b = 100.0 73 | let aMinX = a - x[0] 74 | let yMinXSquared = x[1] - x[0]*x[0] 75 | return aMinX * aMinX + b * yMinXSquared * yMinXSquared 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/xcshareddata/xcschemes/Anomalii-Package.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 76 | 78 | 79 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/xcshareddata/xcschemes/AnomaliiPackageTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/xcshareddata/xcschemes/AnomaliiPackageDescription.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Sources/Anomalii/Evolver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Evolver.swift 3 | // Anomalii 4 | // 5 | // Created by Drew McCormack on 14/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol FitnessEvaluator: class { 11 | func fitness(of expression: Expression) -> Double 12 | } 13 | 14 | class Evolver { 15 | 16 | struct FitnessResult: Hashable { 17 | let populationIndex: Int 18 | let expression: Expression 19 | let fitness: Double 20 | var hashValue: Int { return populationIndex.hashValue } 21 | static func ==(left: FitnessResult, right: FitnessResult) -> Bool { return left.populationIndex == right.populationIndex } 22 | } 23 | 24 | var population: [Expression] 25 | weak var fitnessEvaluator: FitnessEvaluator! 26 | weak var mutator: Mutator! 27 | 28 | init(initialPopulation: [Expression], evaluatingFitnessWith evaluator: FitnessEvaluator, mutatingWith mutator: Mutator) { 29 | self.population = initialPopulation 30 | self.fitnessEvaluator = evaluator 31 | self.mutator = mutator 32 | } 33 | 34 | func evolve() { 35 | let populationSize = population.count 36 | var newPopulation: [Expression] = [] 37 | let fitnessResults = self.fitnessResults() 38 | 39 | // Elitism: the best 1% go direct to the new population 40 | var elitismCandidates = fitnessResults.sorted { $0.fitness > $1.fitness } // Best first 41 | let numberElites = populationSize.portioned(percentage: 1) 42 | let eliteResults = elitismCandidates[0.. [FitnessResult] { 82 | return population.enumerated().map { (index, expression) in 83 | return FitnessResult(populationIndex: index, expression: expression, fitness: fitnessEvaluator.fitness(of: expression)) 84 | } 85 | } 86 | } 87 | 88 | extension Int { 89 | func portioned(percentage: Double) -> Int { 90 | return Int(Double(self) * percentage / 100.0) 91 | } 92 | } 93 | 94 | extension Array where Element == Evolver.FitnessResult { 95 | func fitnessWeightedRandomResult() -> (Evolver.FitnessResult, Int) { 96 | let total: Double = self.reduce(0.0) { $0 + $1.fitness } 97 | let rand = Double.random * total 98 | var sum = 0.0 99 | for (index, result) in self.enumerated() { 100 | sum += result.fitness 101 | if sum >= rand { 102 | return (result, index) 103 | } 104 | } 105 | return (self.last!, self.count-1) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Anomalii.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | "Anomalii::AnomaliiPackageTests::ProductTarget" /* AnomaliiPackageTests */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = OBJ_39 /* Build configuration list for PBXAggregateTarget "AnomaliiPackageTests" */; 13 | buildPhases = ( 14 | ); 15 | dependencies = ( 16 | OBJ_42 /* PBXTargetDependency */, 17 | ); 18 | name = AnomaliiPackageTests; 19 | productName = AnomaliiPackageTests; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | 071BC7811FC8A4E6004C6582 /* CodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071BC7801FC8A4E6004C6582 /* CodableTests.swift */; }; 25 | 0730A90D1FDD999D00A48515 /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0730A90B1FDD999D00A48515 /* Variable.swift */; }; 26 | 0730A9101FDD99A900A48515 /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0730A90E1FDD99A900A48515 /* Constant.swift */; }; 27 | 0730A9131FDD9ADC00A48515 /* VectorValued.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0730A9111FDD9ADC00A48515 /* VectorValued.swift */; }; 28 | 07661FF71FC9B33A004FF591 /* OratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07661FF61FC9B33A004FF591 /* OratorTests.swift */; }; 29 | 07661FF91FCB1DD6004FF591 /* PopulatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07661FF81FCB1DD6004FF591 /* PopulatorTests.swift */; }; 30 | 07661FFB1FCB1FF8004FF591 /* StandardMutatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07661FFA1FCB1FF8004FF591 /* StandardMutatorTests.swift */; }; 31 | 07661FFD1FD08979004FF591 /* RegressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07661FFC1FD08979004FF591 /* RegressionTests.swift */; }; 32 | 076C08241FBDFB33007668CB /* Traversal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 076C08221FBDFB33007668CB /* Traversal.swift */; }; 33 | 0772621E1FE449E700AD7CB7 /* MultidimensionalOptimizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0772621D1FE449E700AD7CB7 /* MultidimensionalOptimizationTests.swift */; }; 34 | 077B391E1FE5376000B648BE /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077B391D1FE5376000B648BE /* General.swift */; }; 35 | 07ACFAC51FBB846300197723 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAC31FBB846300197723 /* Expression.swift */; }; 36 | 07ACFAC81FBB847F00197723 /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAC61FBB847F00197723 /* Operator.swift */; }; 37 | 07ACFACB1FBB84AD00197723 /* ScalarValued.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAC91FBB84AD00197723 /* ScalarValued.swift */; }; 38 | 07ACFACE1FBB84CE00197723 /* ScalarOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFACC1FBB84CE00197723 /* ScalarOperator.swift */; }; 39 | 07ACFAD11FBB84F300197723 /* Terminal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFACF1FBB84F300197723 /* Terminal.swift */; }; 40 | 07ACFAD41FBB851D00197723 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAD21FBB851D00197723 /* Value.swift */; }; 41 | 07ACFAD71FBB854400197723 /* Orator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAD51FBB854400197723 /* Orator.swift */; }; 42 | 07ACFADA1FBB856800197723 /* Populator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAD81FBB856800197723 /* Populator.swift */; }; 43 | 07ACFADD1FBB859400197723 /* Mutator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFADB1FBB859400197723 /* Mutator.swift */; }; 44 | 07ACFAE01FBB85BF00197723 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFADE1FBB85BF00197723 /* Random.swift */; }; 45 | 07ACFAE31FBB85DC00197723 /* Solver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAE11FBB85DC00197723 /* Solver.swift */; }; 46 | 07ACFAE61FBB861400197723 /* Evolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ACFAE41FBB861400197723 /* Evolver.swift */; }; 47 | 07ECE7211FD7243700A04770 /* VectorOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ECE7201FD7243700A04770 /* VectorOperator.swift */; }; 48 | OBJ_21 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; 49 | OBJ_27 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* ExpressionTests.swift */; }; 50 | OBJ_29 /* Anomalii.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Anomalii::Anomalii::Product" /* Anomalii.framework */; }; 51 | OBJ_36 /* Anomalii.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* Anomalii.swift */; }; 52 | /* End PBXBuildFile section */ 53 | 54 | /* Begin PBXContainerItemProxy section */ 55 | 07ACFAC11FBB829000197723 /* PBXContainerItemProxy */ = { 56 | isa = PBXContainerItemProxy; 57 | containerPortal = OBJ_1 /* Project object */; 58 | proxyType = 1; 59 | remoteGlobalIDString = "Anomalii::Anomalii"; 60 | remoteInfo = Anomalii; 61 | }; 62 | 07ACFAC21FBB829100197723 /* PBXContainerItemProxy */ = { 63 | isa = PBXContainerItemProxy; 64 | containerPortal = OBJ_1 /* Project object */; 65 | proxyType = 1; 66 | remoteGlobalIDString = "Anomalii::AnomaliiTests"; 67 | remoteInfo = AnomaliiTests; 68 | }; 69 | /* End PBXContainerItemProxy section */ 70 | 71 | /* Begin PBXFileReference section */ 72 | 071BC7801FC8A4E6004C6582 /* CodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableTests.swift; sourceTree = ""; }; 73 | 0730A90B1FDD999D00A48515 /* Variable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Variable.swift; sourceTree = ""; }; 74 | 0730A90E1FDD99A900A48515 /* Constant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constant.swift; sourceTree = ""; }; 75 | 0730A9111FDD9ADC00A48515 /* VectorValued.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorValued.swift; sourceTree = ""; }; 76 | 07661FF61FC9B33A004FF591 /* OratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OratorTests.swift; sourceTree = ""; }; 77 | 07661FF81FCB1DD6004FF591 /* PopulatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopulatorTests.swift; sourceTree = ""; }; 78 | 07661FFA1FCB1FF8004FF591 /* StandardMutatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardMutatorTests.swift; sourceTree = ""; }; 79 | 07661FFC1FD08979004FF591 /* RegressionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegressionTests.swift; sourceTree = ""; }; 80 | 076C08221FBDFB33007668CB /* Traversal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Traversal.swift; sourceTree = ""; }; 81 | 0772621D1FE449E700AD7CB7 /* MultidimensionalOptimizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultidimensionalOptimizationTests.swift; sourceTree = ""; }; 82 | 077B391D1FE5376000B648BE /* General.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = ""; }; 83 | 07ACFAC31FBB846300197723 /* Expression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; }; 84 | 07ACFAC61FBB847F00197723 /* Operator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operator.swift; sourceTree = ""; }; 85 | 07ACFAC91FBB84AD00197723 /* ScalarValued.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScalarValued.swift; sourceTree = ""; }; 86 | 07ACFACC1FBB84CE00197723 /* ScalarOperator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScalarOperator.swift; sourceTree = ""; }; 87 | 07ACFACF1FBB84F300197723 /* Terminal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Terminal.swift; sourceTree = ""; }; 88 | 07ACFAD21FBB851D00197723 /* Value.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = ""; }; 89 | 07ACFAD51FBB854400197723 /* Orator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Orator.swift; sourceTree = ""; }; 90 | 07ACFAD81FBB856800197723 /* Populator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Populator.swift; sourceTree = ""; }; 91 | 07ACFADB1FBB859400197723 /* Mutator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutator.swift; sourceTree = ""; }; 92 | 07ACFADE1FBB85BF00197723 /* Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; 93 | 07ACFAE11FBB85DC00197723 /* Solver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Solver.swift; sourceTree = ""; }; 94 | 07ACFAE41FBB861400197723 /* Evolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Evolver.swift; sourceTree = ""; }; 95 | 07ECE7201FD7243700A04770 /* VectorOperator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorOperator.swift; sourceTree = ""; }; 96 | "Anomalii::Anomalii::Product" /* Anomalii.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Anomalii.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | "Anomalii::AnomaliiTests::Product" /* AnomaliiTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = AnomaliiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | OBJ_12 /* ExpressionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpressionTests.swift; sourceTree = ""; }; 99 | OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 100 | OBJ_9 /* Anomalii.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Anomalii.swift; sourceTree = ""; }; 101 | /* End PBXFileReference section */ 102 | 103 | /* Begin PBXFrameworksBuildPhase section */ 104 | OBJ_28 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 0; 107 | files = ( 108 | OBJ_29 /* Anomalii.framework in Frameworks */, 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | OBJ_37 /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 0; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXFrameworksBuildPhase section */ 120 | 121 | /* Begin PBXGroup section */ 122 | OBJ_10 /* Tests */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | OBJ_11 /* AnomaliiTests */, 126 | ); 127 | name = Tests; 128 | sourceTree = SOURCE_ROOT; 129 | }; 130 | OBJ_11 /* AnomaliiTests */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | OBJ_12 /* ExpressionTests.swift */, 134 | 071BC7801FC8A4E6004C6582 /* CodableTests.swift */, 135 | 07661FF61FC9B33A004FF591 /* OratorTests.swift */, 136 | 07661FF81FCB1DD6004FF591 /* PopulatorTests.swift */, 137 | 07661FFA1FCB1FF8004FF591 /* StandardMutatorTests.swift */, 138 | 07661FFC1FD08979004FF591 /* RegressionTests.swift */, 139 | 0772621D1FE449E700AD7CB7 /* MultidimensionalOptimizationTests.swift */, 140 | ); 141 | name = AnomaliiTests; 142 | path = Tests/AnomaliiTests; 143 | sourceTree = SOURCE_ROOT; 144 | }; 145 | OBJ_13 /* Products */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | "Anomalii::AnomaliiTests::Product" /* AnomaliiTests.xctest */, 149 | "Anomalii::Anomalii::Product" /* Anomalii.framework */, 150 | ); 151 | name = Products; 152 | path = ..; 153 | sourceTree = BUILT_PRODUCTS_DIR; 154 | }; 155 | OBJ_5 = { 156 | isa = PBXGroup; 157 | children = ( 158 | OBJ_6 /* Package.swift */, 159 | OBJ_7 /* Sources */, 160 | OBJ_10 /* Tests */, 161 | OBJ_13 /* Products */, 162 | ); 163 | sourceTree = ""; 164 | }; 165 | OBJ_7 /* Sources */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | OBJ_8 /* Anomalii */, 169 | ); 170 | name = Sources; 171 | sourceTree = SOURCE_ROOT; 172 | }; 173 | OBJ_8 /* Anomalii */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | OBJ_9 /* Anomalii.swift */, 177 | 07ACFADE1FBB85BF00197723 /* Random.swift */, 178 | 07ACFAD21FBB851D00197723 /* Value.swift */, 179 | 07ACFAC31FBB846300197723 /* Expression.swift */, 180 | 076C08221FBDFB33007668CB /* Traversal.swift */, 181 | 07ACFAC61FBB847F00197723 /* Operator.swift */, 182 | 07ACFAC91FBB84AD00197723 /* ScalarValued.swift */, 183 | 0730A9111FDD9ADC00A48515 /* VectorValued.swift */, 184 | 07ACFACC1FBB84CE00197723 /* ScalarOperator.swift */, 185 | 07ECE7201FD7243700A04770 /* VectorOperator.swift */, 186 | 07ACFACF1FBB84F300197723 /* Terminal.swift */, 187 | 0730A90E1FDD99A900A48515 /* Constant.swift */, 188 | 0730A90B1FDD999D00A48515 /* Variable.swift */, 189 | 07ACFAD51FBB854400197723 /* Orator.swift */, 190 | 07ACFAD81FBB856800197723 /* Populator.swift */, 191 | 07ACFADB1FBB859400197723 /* Mutator.swift */, 192 | 07ACFAE41FBB861400197723 /* Evolver.swift */, 193 | 07ACFAE11FBB85DC00197723 /* Solver.swift */, 194 | 077B391D1FE5376000B648BE /* General.swift */, 195 | ); 196 | name = Anomalii; 197 | path = Sources/Anomalii; 198 | sourceTree = SOURCE_ROOT; 199 | }; 200 | /* End PBXGroup section */ 201 | 202 | /* Begin PBXNativeTarget section */ 203 | "Anomalii::Anomalii" /* Anomalii */ = { 204 | isa = PBXNativeTarget; 205 | buildConfigurationList = OBJ_32 /* Build configuration list for PBXNativeTarget "Anomalii" */; 206 | buildPhases = ( 207 | OBJ_35 /* Sources */, 208 | OBJ_37 /* Frameworks */, 209 | ); 210 | buildRules = ( 211 | ); 212 | dependencies = ( 213 | ); 214 | name = Anomalii; 215 | productName = Anomalii; 216 | productReference = "Anomalii::Anomalii::Product" /* Anomalii.framework */; 217 | productType = "com.apple.product-type.framework"; 218 | }; 219 | "Anomalii::AnomaliiTests" /* AnomaliiTests */ = { 220 | isa = PBXNativeTarget; 221 | buildConfigurationList = OBJ_23 /* Build configuration list for PBXNativeTarget "AnomaliiTests" */; 222 | buildPhases = ( 223 | OBJ_26 /* Sources */, 224 | OBJ_28 /* Frameworks */, 225 | ); 226 | buildRules = ( 227 | ); 228 | dependencies = ( 229 | OBJ_30 /* PBXTargetDependency */, 230 | ); 231 | name = AnomaliiTests; 232 | productName = AnomaliiTests; 233 | productReference = "Anomalii::AnomaliiTests::Product" /* AnomaliiTests.xctest */; 234 | productType = "com.apple.product-type.bundle.unit-test"; 235 | }; 236 | "Anomalii::SwiftPMPackageDescription" /* AnomaliiPackageDescription */ = { 237 | isa = PBXNativeTarget; 238 | buildConfigurationList = OBJ_17 /* Build configuration list for PBXNativeTarget "AnomaliiPackageDescription" */; 239 | buildPhases = ( 240 | OBJ_20 /* Sources */, 241 | ); 242 | buildRules = ( 243 | ); 244 | dependencies = ( 245 | ); 246 | name = AnomaliiPackageDescription; 247 | productName = AnomaliiPackageDescription; 248 | productType = "com.apple.product-type.framework"; 249 | }; 250 | /* End PBXNativeTarget section */ 251 | 252 | /* Begin PBXProject section */ 253 | OBJ_1 /* Project object */ = { 254 | isa = PBXProject; 255 | attributes = { 256 | LastUpgradeCheck = 9999; 257 | }; 258 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "Anomalii" */; 259 | compatibilityVersion = "Xcode 3.2"; 260 | developmentRegion = English; 261 | hasScannedForEncodings = 0; 262 | knownRegions = ( 263 | en, 264 | ); 265 | mainGroup = OBJ_5; 266 | productRefGroup = OBJ_13 /* Products */; 267 | projectDirPath = ""; 268 | projectRoot = ""; 269 | targets = ( 270 | "Anomalii::SwiftPMPackageDescription" /* AnomaliiPackageDescription */, 271 | "Anomalii::AnomaliiTests" /* AnomaliiTests */, 272 | "Anomalii::Anomalii" /* Anomalii */, 273 | "Anomalii::AnomaliiPackageTests::ProductTarget" /* AnomaliiPackageTests */, 274 | ); 275 | }; 276 | /* End PBXProject section */ 277 | 278 | /* Begin PBXSourcesBuildPhase section */ 279 | OBJ_20 /* Sources */ = { 280 | isa = PBXSourcesBuildPhase; 281 | buildActionMask = 0; 282 | files = ( 283 | OBJ_21 /* Package.swift in Sources */, 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | }; 287 | OBJ_26 /* Sources */ = { 288 | isa = PBXSourcesBuildPhase; 289 | buildActionMask = 0; 290 | files = ( 291 | 07661FF91FCB1DD6004FF591 /* PopulatorTests.swift in Sources */, 292 | 07661FF71FC9B33A004FF591 /* OratorTests.swift in Sources */, 293 | 0772621E1FE449E700AD7CB7 /* MultidimensionalOptimizationTests.swift in Sources */, 294 | 07661FFD1FD08979004FF591 /* RegressionTests.swift in Sources */, 295 | 07661FFB1FCB1FF8004FF591 /* StandardMutatorTests.swift in Sources */, 296 | 071BC7811FC8A4E6004C6582 /* CodableTests.swift in Sources */, 297 | OBJ_27 /* ExpressionTests.swift in Sources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | OBJ_35 /* Sources */ = { 302 | isa = PBXSourcesBuildPhase; 303 | buildActionMask = 0; 304 | files = ( 305 | 07ACFAD71FBB854400197723 /* Orator.swift in Sources */, 306 | 0730A9101FDD99A900A48515 /* Constant.swift in Sources */, 307 | OBJ_36 /* Anomalii.swift in Sources */, 308 | 07ACFAE31FBB85DC00197723 /* Solver.swift in Sources */, 309 | 07ACFACB1FBB84AD00197723 /* ScalarValued.swift in Sources */, 310 | 076C08241FBDFB33007668CB /* Traversal.swift in Sources */, 311 | 07ACFAD41FBB851D00197723 /* Value.swift in Sources */, 312 | 07ACFADA1FBB856800197723 /* Populator.swift in Sources */, 313 | 07ACFAC81FBB847F00197723 /* Operator.swift in Sources */, 314 | 07ACFAD11FBB84F300197723 /* Terminal.swift in Sources */, 315 | 07ACFAC51FBB846300197723 /* Expression.swift in Sources */, 316 | 07ACFADD1FBB859400197723 /* Mutator.swift in Sources */, 317 | 07ACFAE61FBB861400197723 /* Evolver.swift in Sources */, 318 | 07ACFACE1FBB84CE00197723 /* ScalarOperator.swift in Sources */, 319 | 07ECE7211FD7243700A04770 /* VectorOperator.swift in Sources */, 320 | 07ACFAE01FBB85BF00197723 /* Random.swift in Sources */, 321 | 0730A9131FDD9ADC00A48515 /* VectorValued.swift in Sources */, 322 | 077B391E1FE5376000B648BE /* General.swift in Sources */, 323 | 0730A90D1FDD999D00A48515 /* Variable.swift in Sources */, 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | /* End PBXSourcesBuildPhase section */ 328 | 329 | /* Begin PBXTargetDependency section */ 330 | OBJ_30 /* PBXTargetDependency */ = { 331 | isa = PBXTargetDependency; 332 | target = "Anomalii::Anomalii" /* Anomalii */; 333 | targetProxy = 07ACFAC11FBB829000197723 /* PBXContainerItemProxy */; 334 | }; 335 | OBJ_42 /* PBXTargetDependency */ = { 336 | isa = PBXTargetDependency; 337 | target = "Anomalii::AnomaliiTests" /* AnomaliiTests */; 338 | targetProxy = 07ACFAC21FBB829100197723 /* PBXContainerItemProxy */; 339 | }; 340 | /* End PBXTargetDependency section */ 341 | 342 | /* Begin XCBuildConfiguration section */ 343 | OBJ_18 /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | LD = /usr/bin/true; 347 | OTHER_SWIFT_FLAGS = "-swift-version 4 -I /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk"; 348 | SWIFT_VERSION = 4.0; 349 | }; 350 | name = Debug; 351 | }; 352 | OBJ_19 /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | LD = /usr/bin/true; 356 | OTHER_SWIFT_FLAGS = "-swift-version 4 -I /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk"; 357 | SWIFT_VERSION = 4.0; 358 | }; 359 | name = Release; 360 | }; 361 | OBJ_24 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 365 | FRAMEWORK_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 368 | ); 369 | HEADER_SEARCH_PATHS = "$(inherited)"; 370 | INFOPLIST_FILE = Anomalii.xcodeproj/AnomaliiTests_Info.plist; 371 | LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; 372 | OTHER_LDFLAGS = "$(inherited)"; 373 | OTHER_SWIFT_FLAGS = "$(inherited)"; 374 | SWIFT_VERSION = 4.0; 375 | TARGET_NAME = AnomaliiTests; 376 | }; 377 | name = Debug; 378 | }; 379 | OBJ_25 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 383 | FRAMEWORK_SEARCH_PATHS = ( 384 | "$(inherited)", 385 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 386 | ); 387 | HEADER_SEARCH_PATHS = "$(inherited)"; 388 | INFOPLIST_FILE = Anomalii.xcodeproj/AnomaliiTests_Info.plist; 389 | LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; 390 | OTHER_LDFLAGS = "$(inherited)"; 391 | OTHER_SWIFT_FLAGS = "$(inherited)"; 392 | SWIFT_VERSION = 4.0; 393 | TARGET_NAME = AnomaliiTests; 394 | }; 395 | name = Release; 396 | }; 397 | OBJ_3 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | CLANG_ENABLE_OBJC_ARC = YES; 401 | COMBINE_HIDPI_IMAGES = YES; 402 | COPY_PHASE_STRIP = NO; 403 | DEBUG_INFORMATION_FORMAT = dwarf; 404 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 405 | ENABLE_NS_ASSERTIONS = YES; 406 | GCC_OPTIMIZATION_LEVEL = 0; 407 | MACOSX_DEPLOYMENT_TARGET = 10.10; 408 | ONLY_ACTIVE_ARCH = YES; 409 | OTHER_SWIFT_FLAGS = "-DXcode"; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | SDKROOT = macosx; 412 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; 413 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; 414 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 415 | USE_HEADERMAP = NO; 416 | }; 417 | name = Debug; 418 | }; 419 | OBJ_33 /* Debug */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | ENABLE_TESTABILITY = YES; 423 | FRAMEWORK_SEARCH_PATHS = ( 424 | "$(inherited)", 425 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 426 | ); 427 | HEADER_SEARCH_PATHS = "$(inherited)"; 428 | INFOPLIST_FILE = Anomalii.xcodeproj/Anomalii_Info.plist; 429 | LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; 430 | OTHER_LDFLAGS = "$(inherited)"; 431 | OTHER_SWIFT_FLAGS = "$(inherited)"; 432 | PRODUCT_BUNDLE_IDENTIFIER = Anomalii; 433 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 434 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 435 | SKIP_INSTALL = YES; 436 | SWIFT_VERSION = 4.0; 437 | TARGET_NAME = Anomalii; 438 | }; 439 | name = Debug; 440 | }; 441 | OBJ_34 /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | ENABLE_TESTABILITY = YES; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(inherited)", 447 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 448 | ); 449 | HEADER_SEARCH_PATHS = "$(inherited)"; 450 | INFOPLIST_FILE = Anomalii.xcodeproj/Anomalii_Info.plist; 451 | LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; 452 | OTHER_LDFLAGS = "$(inherited)"; 453 | OTHER_SWIFT_FLAGS = "$(inherited)"; 454 | PRODUCT_BUNDLE_IDENTIFIER = Anomalii; 455 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 456 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 457 | SKIP_INSTALL = YES; 458 | SWIFT_VERSION = 4.0; 459 | TARGET_NAME = Anomalii; 460 | }; 461 | name = Release; 462 | }; 463 | OBJ_4 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | CLANG_ENABLE_OBJC_ARC = YES; 467 | COMBINE_HIDPI_IMAGES = YES; 468 | COPY_PHASE_STRIP = YES; 469 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 470 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 471 | GCC_OPTIMIZATION_LEVEL = s; 472 | MACOSX_DEPLOYMENT_TARGET = 10.10; 473 | OTHER_SWIFT_FLAGS = "-DXcode"; 474 | PRODUCT_NAME = "$(TARGET_NAME)"; 475 | SDKROOT = macosx; 476 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; 477 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; 478 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 479 | USE_HEADERMAP = NO; 480 | }; 481 | name = Release; 482 | }; 483 | OBJ_40 /* Debug */ = { 484 | isa = XCBuildConfiguration; 485 | buildSettings = { 486 | }; 487 | name = Debug; 488 | }; 489 | OBJ_41 /* Release */ = { 490 | isa = XCBuildConfiguration; 491 | buildSettings = { 492 | }; 493 | name = Release; 494 | }; 495 | /* End XCBuildConfiguration section */ 496 | 497 | /* Begin XCConfigurationList section */ 498 | OBJ_17 /* Build configuration list for PBXNativeTarget "AnomaliiPackageDescription" */ = { 499 | isa = XCConfigurationList; 500 | buildConfigurations = ( 501 | OBJ_18 /* Debug */, 502 | OBJ_19 /* Release */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Debug; 506 | }; 507 | OBJ_2 /* Build configuration list for PBXProject "Anomalii" */ = { 508 | isa = XCConfigurationList; 509 | buildConfigurations = ( 510 | OBJ_3 /* Debug */, 511 | OBJ_4 /* Release */, 512 | ); 513 | defaultConfigurationIsVisible = 0; 514 | defaultConfigurationName = Debug; 515 | }; 516 | OBJ_23 /* Build configuration list for PBXNativeTarget "AnomaliiTests" */ = { 517 | isa = XCConfigurationList; 518 | buildConfigurations = ( 519 | OBJ_24 /* Debug */, 520 | OBJ_25 /* Release */, 521 | ); 522 | defaultConfigurationIsVisible = 0; 523 | defaultConfigurationName = Debug; 524 | }; 525 | OBJ_32 /* Build configuration list for PBXNativeTarget "Anomalii" */ = { 526 | isa = XCConfigurationList; 527 | buildConfigurations = ( 528 | OBJ_33 /* Debug */, 529 | OBJ_34 /* Release */, 530 | ); 531 | defaultConfigurationIsVisible = 0; 532 | defaultConfigurationName = Debug; 533 | }; 534 | OBJ_39 /* Build configuration list for PBXAggregateTarget "AnomaliiPackageTests" */ = { 535 | isa = XCConfigurationList; 536 | buildConfigurations = ( 537 | OBJ_40 /* Debug */, 538 | OBJ_41 /* Release */, 539 | ); 540 | defaultConfigurationIsVisible = 0; 541 | defaultConfigurationName = Debug; 542 | }; 543 | /* End XCConfigurationList section */ 544 | }; 545 | rootObject = OBJ_1 /* Project object */; 546 | } 547 | --------------------------------------------------------------------------------