├── 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 |
--------------------------------------------------------------------------------