├── Simple-Swift-AI
├── Simple-Swift-AI
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── simpleSwiftAI-29.png
│ │ │ ├── simpleSwiftAI-40.png
│ │ │ ├── simpleSwiftAI-76.png
│ │ │ ├── simpleSwiftAI-29@2x.png
│ │ │ ├── simpleSwiftAI-29@3x.png
│ │ │ ├── simpleSwiftAI-40@2x.png
│ │ │ ├── simpleSwiftAI-40@3x.png
│ │ │ ├── simpleSwiftAI-60@2x.png
│ │ │ ├── simpleSwiftAI-60@3x.png
│ │ │ ├── simpleSwiftAI-76@2x.png
│ │ │ ├── simpleSwiftAI-83.5@2x.png
│ │ │ └── Contents.json
│ ├── Simple_Swift_AI.xcdatamodeld
│ │ ├── .xccurrentversion
│ │ └── Simple_Swift_AI.xcdatamodel
│ │ │ └── contents
│ ├── Network
│ │ ├── ActivationFunctions.swift
│ │ ├── InputA.swift
│ │ ├── NeuronA.swift
│ │ ├── AutoNetworkBuilder.swift
│ │ └── NetworkA.swift
│ ├── ViewController.swift
│ ├── DebugView
│ │ ├── OutputTableViewCell.swift
│ │ ├── NeuronInputsView.swift
│ │ ├── OutputTableController.swift
│ │ └── NetworkViewController.swift
│ ├── Utils
│ │ ├── Utils.swift
│ │ └── CoreDataUtil.swift
│ ├── Examples
│ │ └── AI_System_XOR.swift
│ ├── Info.plist
│ ├── AppDelegate.swift
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
└── Simple-Swift-AI.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── project.pbxproj
├── LICENSE
├── README.md
└── .gitignore
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-29.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-40.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-76.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-29@2x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-29@3x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-40@2x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-40@3x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-60@2x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-60@3x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-76@2x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arjungupta99/Simple-Swift-AI/HEAD/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/simpleSwiftAI-83.5@2x.png
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Simple_Swift_AI.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | Simple_Swift_AI.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Network/ActivationFunctions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ActivationFunctions.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 7/29/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class ActivationFunctions {
12 |
13 |
14 | class func linear(x: Double) -> Double {
15 | return x
16 | }
17 |
18 | class func sigmoid(val: Double) -> Double {
19 | return 1 / (1 + exp(-val))
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/30/16.
6 | // Copyright © 2016 Arjun Gupta. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let _ = AI_System_XOR(rootVC:self)
17 |
18 | }
19 |
20 | override func didReceiveMemoryWarning() {
21 | super.didReceiveMemoryWarning()
22 | // Dispose of any resources that can be recreated.
23 | }
24 |
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/DebugView/OutputTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OutputTableViewCell.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/27/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class OutputTableViewCell:UITableViewCell {
13 |
14 | @IBOutlet weak var cellIndexLabel : UILabel!
15 | @IBOutlet weak var inputLabelView : UIView!
16 | @IBOutlet weak var outputLabelView : UIView!
17 |
18 |
19 | var inputLabels = [UILabel]()
20 | var outputLabels = [UILabel]()
21 | var inputNeuronLabels = [UILabel]()
22 | var outputNeuronLabels = [UILabel]()
23 | }
24 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Simple_Swift_AI.xcdatamodeld/Simple_Swift_AI.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Utils/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 7/29/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class Utils {
13 |
14 | }
15 |
16 | func DebugLog(_ logMessage: String, className: String = #file, lineNumber: NSInteger = #line) {
17 | let tempArr = className.characters.split(separator: "/").map(String.init)
18 | let last = tempArr[tempArr.count-1]
19 | print("\(last) ... Line: \(lineNumber) ... \(logMessage)", terminator: "\n")
20 | }
21 |
22 |
23 | extension Double {
24 |
25 | func roundToDigits(digits:Int) -> Double {
26 | let divisor = pow(10.0, Double(digits))
27 | return (self * divisor).rounded() / divisor
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Network/InputA.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InputA.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 7/29/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | @objc class InputA:NSObject {
13 |
14 | var weight :Double
15 | var neuron :NeuronA?
16 | var value :Double? {
17 | set (newValue) { self.valueStore = newValue }
18 | get { return (self.neuron != nil) ? self.neuron!.output! : self.valueStore }
19 | }
20 | private var valueStore:Double?
21 | var indexInLayer:Int = 0
22 |
23 | //Input layer
24 | init(value:Double, weight:Double) {
25 | self.weight = weight
26 | super.init()
27 | self.value = value
28 | }
29 |
30 | //Hidden layer
31 | init(neuron:NeuronA, weight:Double) {
32 | self.neuron = neuron
33 | self.weight = weight
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Arjun Gupta
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Simple-Swift-AI
2 | A simple to use Feed Forward Neural Network built in Swift 3.0
3 |
4 | ### Usage
5 | * A data set with multiple inputs and outputs can be used to train the network.
6 | * The default number of hidden layers is one, more can be added as per need.
7 | * The neuron output values range from 0 to 1.0. Modify your data set accordingly.
8 |
9 | ### Features
10 | * Feed-forward neural network with input, hidden and output layers
11 | * Multiple hidden layers can be added with little extra code
12 | * Can come in use for categorization and function value prediction
13 | * Optional debug screen included for viewing the training and test outputs on simulator
14 |
15 | ---
16 | An example of XOR gate training is included.
17 |
18 | ---
19 |
20 |
21 | **FFNN Training screen**
22 |
23 | 
24 |
25 | ---
26 |
27 | **FFNN Test screen**
28 |
29 | 
30 |
31 | ---
32 |
33 | By Arjun Gupta
34 |
35 | Can be reached at : arjungupta497 (at) gmail.com
36 |
37 | Twitter : https://www.twitter.com/arjunguptaxor
38 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Examples/AI_System_XOR.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AI_System_XOR.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/23/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class AI_System_XOR {
13 |
14 | init(rootVC:UIViewController?) {
15 |
16 | //Building a large training set using the same four Input and Outputs of XOR Gate
17 |
18 | var trainingSet:[(input:[Double],output:[Double])] =
19 | [
20 | ([0, 0], [0]),
21 | ([0, 1], [1]),
22 | ([1, 0], [1]),
23 | ([1, 1], [0])
24 | ]
25 |
26 | for _ in stride(from: 0, to: 70000, by: 1) {
27 | let randomIndex = Int(arc4random_uniform(4))
28 | trainingSet.append(trainingSet[randomIndex])
29 | }
30 |
31 | let network = AutoNetworkBuilder().buildAutoNetwork(trainingSet: trainingSet, rootVC: rootVC, persistanceID: "XOR")
32 |
33 | network.trainNetwork(trainingSets: trainingSet) { (completion) in
34 |
35 | //Test your inputs here
36 |
37 | if (completion.0 == true) {
38 | DebugLog("Test output -> 0 1 1 0")
39 | let _ = network.getOutputFor(inputs: [[0 , 0],[0 , 1],[1 , 0],[1 , 1]])
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Network/NeuronA.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NeuronA.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 7/29/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | @objc class NeuronA:NSObject {
13 |
14 | var identifier :String
15 | var inputs = [String:InputA]()
16 | var bias :Double?
17 | var output :Double?
18 | var error :Double?
19 |
20 | //Input Neuron
21 | init(uid:String) {
22 | self.identifier = uid
23 | }
24 |
25 | //Hidden Neuron
26 | init(uid:String, bias:Double , inputs:[InputA]? = nil) {
27 | self.identifier = uid
28 | self.bias = bias
29 | super.init()
30 | if let theInputs = inputs {
31 | self.attachInputs(inputs: theInputs)
32 | self.calculateOutput()
33 | }
34 | }
35 |
36 | func attachInputs(inputs:[InputA]) {
37 | for input in inputs {
38 | self.inputs[input.neuron!.identifier] = input
39 | }
40 | }
41 |
42 | func calculateOutput() {
43 |
44 | if (self.inputs.keys.count == 0) { return }
45 |
46 | var inputWeightSummation:Double = 0
47 | for input in self.inputs.values {
48 | inputWeightSummation += (input.value! * input.weight)
49 | }
50 |
51 | let net = inputWeightSummation + self.bias!
52 | self.output = ActivationFunctions.sigmoid(val:net)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/.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 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | # Pods/
47 |
48 | # Carthage
49 | #
50 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
51 | # Carthage/Checkouts
52 |
53 | Carthage/Build
54 |
55 | # fastlane
56 | #
57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
58 | # screenshots whenever they are needed.
59 | # For more information about the recommended setup visit:
60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
61 |
62 | fastlane/report.xml
63 | fastlane/Preview.html
64 | fastlane/screenshots
65 | fastlane/test_output
66 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Simple-AI
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Network/AutoNetworkBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AutoNetworkBuilder.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/23/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | //******************************************************************************
10 | //
11 | // - This class is a quick and simple way to train and test a network.
12 | // - It checks the number of inputs and outputs of the training set to select
13 | // the number of neurons in Input, Hidden and Output layers.
14 | // - Follow the code below when making a custom network
15 | //
16 | //******************************************************************************
17 |
18 | import Foundation
19 | import UIKit
20 |
21 | class AutoNetworkBuilder {
22 |
23 | var aNetwork:NetworkA?
24 |
25 | func buildAutoNetwork(trainingSet:[(input:[Double],output:[Double])], rootVC:UIViewController? = nil, persistanceID:String? = nil) -> NetworkA {
26 |
27 | let network = NetworkA(rootVC:rootVC, persistanceID:persistanceID)
28 | self.aNetwork = network
29 | network.learningRate = 0.5
30 |
31 | let infoSet = trainingSet[0]
32 |
33 | //Input layer
34 | for i in stride(from:0, to:infoSet.input.count, by:1) {
35 |
36 | let identifier = "I" + String(i)
37 | let neuron = NeuronA(uid:identifier)
38 | network.insert(neuron: neuron, layerNum: 0)
39 | }
40 |
41 | //Hidden layer
42 | for i in stride(from:0, to:infoSet.input.count * 3, by:1) {
43 |
44 | let identifier = "H1-" + String(i)
45 | let neuron = NeuronA(uid: identifier, bias: 0.35)
46 | network.insert(neuron: neuron, layerNum: 1)
47 | }
48 |
49 | //Output layer
50 | for i in stride(from:0, to:infoSet.output.count, by:1) {
51 |
52 | let identifier = "O" + String(i)
53 | let neuron = NeuronA(uid:identifier, bias: 0.6)
54 | network.insert(neuron: neuron, layerNum: 2)
55 | }
56 |
57 | network.connectNeuronsWithRandomizedWeights()
58 |
59 | return network
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/30/16.
6 | // Copyright © 2016 Arjun Gupta. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreData
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 | lazy var coreDataUtil = CoreDataUtil()
17 |
18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
19 | // Override point for customization after application launch.
20 | return true
21 | }
22 |
23 | func applicationWillResignActive(_ application: UIApplication) {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
26 | }
27 |
28 | func applicationDidEnterBackground(_ application: UIApplication) {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | func applicationWillEnterForeground(_ application: UIApplication) {
34 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | func applicationDidBecomeActive(_ application: UIApplication) {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | func applicationWillTerminate(_ application: UIApplication) {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | // Saves changes in the application's managed object context before the application terminates.
44 | self.coreDataUtil.saveContext()
45 | }
46 |
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "size" : "29x29",
15 | "idiom" : "iphone",
16 | "filename" : "simpleSwiftAI-29@2x.png",
17 | "scale" : "2x"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "iphone",
22 | "filename" : "simpleSwiftAI-29@3x.png",
23 | "scale" : "3x"
24 | },
25 | {
26 | "size" : "40x40",
27 | "idiom" : "iphone",
28 | "filename" : "simpleSwiftAI-40@2x.png",
29 | "scale" : "2x"
30 | },
31 | {
32 | "size" : "40x40",
33 | "idiom" : "iphone",
34 | "filename" : "simpleSwiftAI-40@3x.png",
35 | "scale" : "3x"
36 | },
37 | {
38 | "size" : "60x60",
39 | "idiom" : "iphone",
40 | "filename" : "simpleSwiftAI-60@2x.png",
41 | "scale" : "2x"
42 | },
43 | {
44 | "size" : "60x60",
45 | "idiom" : "iphone",
46 | "filename" : "simpleSwiftAI-60@3x.png",
47 | "scale" : "3x"
48 | },
49 | {
50 | "idiom" : "ipad",
51 | "size" : "20x20",
52 | "scale" : "1x"
53 | },
54 | {
55 | "idiom" : "ipad",
56 | "size" : "20x20",
57 | "scale" : "2x"
58 | },
59 | {
60 | "size" : "29x29",
61 | "idiom" : "ipad",
62 | "filename" : "simpleSwiftAI-29.png",
63 | "scale" : "1x"
64 | },
65 | {
66 | "size" : "29x29",
67 | "idiom" : "ipad",
68 | "filename" : "simpleSwiftAI-29@2x.png",
69 | "scale" : "2x"
70 | },
71 | {
72 | "size" : "40x40",
73 | "idiom" : "ipad",
74 | "filename" : "simpleSwiftAI-40.png",
75 | "scale" : "1x"
76 | },
77 | {
78 | "size" : "40x40",
79 | "idiom" : "ipad",
80 | "filename" : "simpleSwiftAI-40@2x.png",
81 | "scale" : "2x"
82 | },
83 | {
84 | "size" : "76x76",
85 | "idiom" : "ipad",
86 | "filename" : "simpleSwiftAI-76.png",
87 | "scale" : "1x"
88 | },
89 | {
90 | "size" : "76x76",
91 | "idiom" : "ipad",
92 | "filename" : "simpleSwiftAI-76@2x.png",
93 | "scale" : "2x"
94 | },
95 | {
96 | "size" : "83.5x83.5",
97 | "idiom" : "ipad",
98 | "filename" : "simpleSwiftAI-83.5@2x.png",
99 | "scale" : "2x"
100 | }
101 | ],
102 | "info" : {
103 | "version" : 1,
104 | "author" : "xcode"
105 | }
106 | }
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Utils/CoreDataUtil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoreDataUtil.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 10/2/16.
6 | // Copyright © 2016 Arjun Gupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | class CoreDataUtil {
13 |
14 | lazy var persistentContainer: NSPersistentContainer = {
15 |
16 | let container = NSPersistentContainer(name: "Simple_Swift_AI")
17 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in
18 | if let error = error {
19 |
20 | fatalError("Error: \(error)")
21 | }
22 | })
23 | return container
24 | }()
25 |
26 | func saveContext() {
27 |
28 | let context = persistentContainer.viewContext
29 |
30 | context.reset()
31 |
32 | if context.hasChanges {
33 | do {
34 | try context.save()
35 | } catch let error as NSError {
36 |
37 | fatalError("Error: \(error), \(error.userInfo)")
38 | }
39 | }
40 | }
41 |
42 |
43 | func persistNewWeights(neurons:[[NeuronA]], persistanceID:String) {
44 |
45 | let context = persistentContainer.viewContext
46 | var layers = [[[String:Double]]]()
47 | for layer in neurons {
48 |
49 | var aLayer = [[String:Double]]()
50 | for neuron in layer {
51 | var inputIdentifiers = [String:Double]()
52 | for input in neuron.inputs {
53 | inputIdentifiers[input.key] = input.value.weight
54 | }
55 | aLayer.append(inputIdentifiers)
56 | }
57 | layers.append(aLayer)
58 | }
59 |
60 |
61 | let nObj = NetworkObj(context: context)
62 | nObj.persistanceID = persistanceID
63 | let arrayData = NSKeyedArchiver.archivedData(withRootObject: layers)
64 | nObj.neurons = arrayData as NSData?
65 |
66 | do {
67 | try context.save()
68 | } catch {
69 | fatalError("Failed to save context: \(error)")
70 | }
71 |
72 | }
73 |
74 |
75 | func fetchExistingWeights(persistanceID:String) -> [[[String:Double]]]? {
76 |
77 | let context = persistentContainer.viewContext
78 | let request:NSFetchRequest = NSFetchRequest(entityName: "NetworkObj")
79 |
80 | request.predicate = NSPredicate(format: "persistanceID == %@", persistanceID)
81 |
82 | var result:[[[String:Double]]]?
83 | do {
84 | let results = try context.fetch(request)
85 | if let res = results.last {
86 | if let arr = res as? NetworkObj {
87 |
88 | //DebugLog("nObj.objectID acc : \(arr.objectID.description)")
89 | if let ar = NSKeyedUnarchiver.unarchiveObject(with: arr.neurons! as Data) as? [[[String:Double]]] {
90 |
91 | result = ar
92 | }
93 | }
94 | }
95 |
96 | } catch let error as NSError {
97 | print("Failure to fetch \(error), \(error.userInfo)")
98 | }
99 |
100 | return result
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
30 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/DebugView/NeuronInputsView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NeuronInputsView.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/22/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class NeuronInputsView:UIView {
13 |
14 | var idLabel :UILabel!
15 | var biasLabel :UILabel!
16 | var inputLabels = [String:UILabel]()
17 | var circleView:UIView!
18 |
19 | override init(frame: CGRect) {
20 | super.init(frame: frame)
21 |
22 | let f = CGRect(x: 0, y: 0, width: 60, height: 60)
23 |
24 | self.circleView = UIView(frame: f)
25 | self.circleView.backgroundColor = UIColor.lightGray
26 | self.circleView.backgroundColor = UIColor(red: 1.0, green: 0.39, blue: 0.39, alpha: 1.0)
27 | self.circleView.layer.cornerRadius = f.size.height/2
28 | self.circleView.center = CGPoint(x: frame.size.width - f.size.width/2 - 10, y: frame.size.height/2)
29 | self.addSubview(self.circleView)
30 |
31 | self.idLabel = NeuronInputsView.makeLabel(f: f)
32 | self.idLabel.center = CGPoint(x: f.size.width/2, y: f.size.height/2)
33 | self.circleView.addSubview(self.idLabel)
34 | self.idLabel.center = CGPoint(x: f.size.width/2, y: f.size.height/2)
35 |
36 | self.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 0.9)
37 | }
38 |
39 |
40 | required init?(coder aDecoder: NSCoder) {
41 | fatalError("init(coder:) has not been implemented")
42 | }
43 |
44 |
45 | func buildInputs(inputs:[InputA]) {
46 |
47 | let vMargin:CGFloat = 25
48 | let hMargin:CGFloat = 5
49 | let hLabelMargin:CGFloat = 10
50 | let lbHeight:CGFloat = 16
51 | let lbWidth:CGFloat = self.circleView.frame.origin.x - 2*hLabelMargin
52 | var labelBase:UIView?
53 | if inputs.count > 0 {
54 | labelBase = UIView(frame:CGRect(x: hMargin, y: vMargin, width: lbWidth + hMargin, height: self.bounds.size.height - 2*vMargin))
55 | labelBase?.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.3)
56 | self.addSubview(labelBase!)
57 | }
58 |
59 | let topBase = UIView(frame:CGRect(x: 0, y: 0, width: self.bounds.size.width, height: vMargin - 5))
60 | topBase.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05)
61 | self.addSubview(topBase)
62 |
63 | let bottomBase = UIView(frame:CGRect(x: 0, y: self.bounds.size.height - vMargin + 5, width: self.bounds.size.width, height: vMargin - 5))
64 | bottomBase.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05)
65 | self.addSubview(bottomBase)
66 |
67 | if inputs.count > 0 {
68 | let wf = CGRect(x: 7, y: 0, width: 100, height: vMargin - 3)
69 | let weightLabel = self.makeWeightsLabel(f: wf)
70 | weightLabel.textColor = UIColor.gray
71 | weightLabel.font = UIFont(name: "Helvetica", size: 13)
72 | weightLabel.text = "WEIGHTS"
73 | topBase.addSubview(weightLabel)
74 | }
75 |
76 | let bf = CGRect(x: 0, y: 0, width: self.bounds.size.width - 10, height: vMargin - 3)
77 | self.biasLabel = self.makeWeightsLabel(f: bf)
78 | self.biasLabel.textColor = UIColor(red: 1.0, green: 0.39, blue: 0.39, alpha: 1.0)
79 | self.biasLabel.font = UIFont(name: "Helvetica", size: 13)
80 | self.biasLabel.textAlignment = .right
81 | bottomBase.addSubview(self.biasLabel)
82 |
83 | //Input labels
84 | for (_,input) in inputs.enumerated() {
85 | let f = CGRect(x: 0, y: 0, width: lbWidth, height: lbHeight)
86 | let lb = self.makeWeightsLabel(f: f)
87 | lb.center = CGPoint(x: 5 + lb.frame.size.width/2, y: 5 + lb.frame.size.height * CGFloat(input.indexInLayer) + lb.frame.size.height / 2)
88 | labelBase?.addSubview(lb)
89 | if let neuron = input.neuron {
90 | lb.text = neuron.identifier + " : " + String(input.weight)
91 | self.inputLabels[neuron.identifier] = lb
92 |
93 | if let theBias = neuron.bias {
94 | biasLabel.text = "BIAS \(theBias)"
95 | }
96 | }
97 | }
98 | }
99 |
100 |
101 | func makeWeightsLabel(f:CGRect) -> UILabel {
102 | let lb = NeuronInputsView.makeLabel(f: f)
103 | lb.frame = f
104 | lb.font = UIFont(name: "Helvetica", size: 13)
105 | lb.textColor = UIColor.black
106 | lb.textAlignment = .left
107 | lb.adjustsFontSizeToFitWidth = false
108 | lb.minimumScaleFactor = 1.0
109 | return lb
110 | }
111 |
112 |
113 | class func makeLabel(f:CGRect) -> UILabel {
114 | let lbl = UILabel(frame:f)
115 | lbl.font = UIFont(name: "Helvetica", size: 20)
116 | lbl.minimumScaleFactor = 0.5
117 | lbl.textColor = UIColor.white
118 | lbl.textAlignment = .center
119 | lbl.adjustsFontSizeToFitWidth = true
120 | return lbl
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/DebugView/OutputTableController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OutputTableController.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/27/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class OutputTableController:UITableViewController {
13 |
14 | var inputs :[[Double]]!
15 | var outputs :[[Double]]!
16 | var layers :[[NeuronA]]!
17 | private let neuronWidth :CGFloat = 35
18 | private let labelHeight :CGFloat = 50
19 | private let labelMargin :CGFloat = 10
20 | private let labelTopMargin :CGFloat = 30
21 | private let labelBottomMargin :CGFloat = 20
22 | private let labelSideMargin :CGFloat = 55
23 | private var cellHeight :CGFloat = 100
24 |
25 | override func viewDidLoad() {
26 | super.viewDidLoad()
27 |
28 | let bbi = UIBarButtonItem(title: "Close", style: .plain, target: self, action: #selector(self.closeButtonHandle))
29 | self.navigationItem.rightBarButtonItem = bbi
30 | self.navigationItem.rightBarButtonItem?.tintColor = UIColor.black
31 | self.navigationItem.title = "Test results"
32 | }
33 |
34 | override func viewWillAppear(_ animated: Bool) {
35 | super.viewWillAppear(animated)
36 |
37 | let maxNeurons = max(self.inputs[0].count, self.outputs[0].count)
38 | self.cellHeight = self.labelTopMargin + self.labelHeight * CGFloat(maxNeurons) + self.labelMargin * CGFloat(maxNeurons - 1) + self.labelBottomMargin
39 | }
40 |
41 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
42 |
43 | return inputs.count
44 | }
45 |
46 | override func numberOfSections(in tableView: UITableView) -> Int {
47 |
48 | return 1
49 | }
50 |
51 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
52 |
53 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! OutputTableViewCell
54 |
55 |
56 | cell.contentView.backgroundColor = (indexPath.row % 2 == 0) ? UIColor.white : UIColor(red: 0.97, green: 0.97, blue: 0.97, alpha: 1.0)
57 | cell.cellIndexLabel.text = String(indexPath.row)
58 |
59 | if (cell.inputLabels.count == 0) {
60 |
61 | let f = cell.frame
62 | let labelWidth = f.size.width/2 - 2 * self.neuronWidth
63 | cell.contentView.frame = CGRect(x: 0, y: 0, width: f.size.width, height: f.size.height)
64 |
65 | //Init input labels
66 | for i in stride(from:0, to:self.inputs[0].count, by:1) {
67 |
68 | //Input label
69 | let fi = CGRect(x: self.labelSideMargin, y: self.labelTopMargin + CGFloat(i) * self.labelHeight, width: labelWidth, height: self.labelHeight)
70 | let ilbl = self.makeLabel(f: fi)
71 | ilbl.textAlignment = .left
72 | cell.inputLabelView.addSubview(ilbl)
73 | cell.inputLabels.append(ilbl)
74 |
75 | //Input neuron label
76 | var fni = fi
77 | fni.origin.x -= (self.neuronWidth + 10)
78 | fni.size.width = self.neuronWidth
79 | fni.size.height = self.neuronWidth
80 | fni.origin.y = fi.midY - self.neuronWidth/2
81 | let inlbl = self.makesSmallLabel(f: fni)
82 | cell.inputLabelView.addSubview(inlbl)
83 | cell.inputNeuronLabels.append(inlbl)
84 |
85 | }
86 |
87 | //Init output labels
88 | for i in stride(from:0, to:self.outputs[0].count, by:1) {
89 |
90 | let fo = CGRect(x: self.labelSideMargin, y: self.labelTopMargin + CGFloat(i) * self.labelHeight, width: labelWidth, height: self.labelHeight)
91 | let olbl = self.makeLabel(f: fo)
92 | olbl.textAlignment = .left
93 | cell.outputLabelView.addSubview(olbl)
94 | cell.outputLabels.append(olbl)
95 |
96 | //Output neuron label
97 | var fno = fo
98 | fno.origin.x -= (self.neuronWidth + 10)
99 | fno.size.width = self.neuronWidth
100 | fno.size.height = self.neuronWidth
101 | fno.origin.y = fo.midY - self.neuronWidth/2
102 | let onlbl = self.makesSmallLabel(f: fno)
103 | onlbl.backgroundColor = UIColor(red: 1.0, green: 0.39, blue: 0.39, alpha: 1.0)
104 | cell.outputLabelView.addSubview(onlbl)
105 | cell.outputNeuronLabels.append(onlbl)
106 | }
107 | }
108 |
109 | for i in stride(from:0, to:self.inputs[0].count, by:1) {
110 |
111 | //Input label
112 | let ilbl = cell.inputLabels[i]
113 | let inputVal = String(describing: self.inputs[indexPath.row][i])
114 | ilbl.text = inputVal
115 |
116 | //Input neuron label
117 | let inlbl = cell.inputNeuronLabels[i]
118 | let inputNeuronVal = String(describing: self.layers[0][i].identifier)
119 | inlbl.text = inputNeuronVal
120 | }
121 |
122 | for i in stride(from:0, to:self.outputs[0].count, by:1) {
123 |
124 | //Output label
125 | let olbl = cell.outputLabels[i]
126 |
127 | let outputValue = self.outputs[indexPath.row][i]
128 | let outputVal = String(format:"%f", outputValue)
129 | olbl.text = outputVal
130 |
131 | //Output neuron label
132 | let onlbl = cell.outputNeuronLabels[i]
133 | let outputNeuronVal = String(describing: self.layers[self.layers.count-1][i].identifier)
134 | onlbl.text = outputNeuronVal
135 | }
136 |
137 | return cell
138 | }
139 |
140 |
141 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
142 |
143 | return self.cellHeight
144 | }
145 |
146 |
147 | func closeButtonHandle() {
148 |
149 | self.dismiss(animated: true) {
150 |
151 | }
152 | }
153 |
154 | private func makeLabel(f:CGRect) -> UILabel {
155 | let lb = NeuronInputsView.makeLabel(f: f)
156 | lb.font = UIFont(name: "Helvetica", size: 41)
157 | lb.textColor = UIColor(red: 0.07, green: 0.47, blue: 0.81, alpha: 1.0)
158 | lb.textAlignment = .left
159 | //lb.backgroundColor = UIColor.orange
160 | return lb
161 | }
162 |
163 | private func makesSmallLabel(f:CGRect) -> UILabel {
164 | let lb = NeuronInputsView.makeLabel(f: f)
165 | lb.font = UIFont(name: "Helvetica", size: 17)
166 | lb.textColor = UIColor.white
167 | lb.textAlignment = .center
168 | lb.backgroundColor = UIColor(red: 1.0, green: 0.83, blue: 0.39, alpha: 1.0)
169 | lb.layer.cornerRadius = f.size.width/2
170 | lb.clipsToBounds = true
171 | return lb
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/DebugView/NetworkViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkViewController.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 9/21/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class NetworkViewController:UIViewController {
13 |
14 |
15 | @IBOutlet weak var networkContainer : UIView!
16 | @IBOutlet weak var infoLabel : UILabel!
17 | @IBOutlet weak var learningRateLabel : UILabel!
18 | @IBOutlet weak var scrollView : UIScrollView!
19 | @IBOutlet weak var progressBar : UIProgressView!
20 | @IBOutlet weak var trainingProgressLabel: UILabel!
21 | @IBOutlet weak var testInputsButton : UIButton!
22 |
23 |
24 | var neuronViews = [String:NeuronInputsView]()
25 | weak var parentView:UIView?
26 | private let outputTableController = OutputTableController()
27 | private var testInputs :[[Double]]?
28 | private var testOutputs :[[Double]]?
29 | private var testLayers :[[NeuronA]]?
30 |
31 |
32 | class func loadVC(rootVC:UIViewController) -> NetworkViewController {
33 |
34 | let storyboard = UIStoryboard(name: "Main", bundle: nil)
35 | let vc = storyboard.instantiateViewController(withIdentifier: "id_networkVC") as! NetworkViewController
36 |
37 | let navController = UINavigationController(rootViewController: vc)
38 |
39 | rootVC.present(navController, animated: false, completion: nil)
40 |
41 | vc.automaticallyAdjustsScrollViewInsets = false
42 |
43 | return vc
44 | }
45 |
46 |
47 | //MARK:- View Setup
48 |
49 |
50 |
51 | override func viewDidLoad() {
52 | super.viewDidLoad()
53 |
54 | self.navigationItem.title = "Simple Swift AI - FFNN"
55 | }
56 |
57 |
58 | func buildView(layers:[[NeuronA]], learningRate:CGFloat) {
59 |
60 | self.progressBar?.isHidden = false
61 | self.trainingProgressLabel?.isHidden = false
62 | self.testInputsButton?.isHidden = true
63 |
64 | let cSize = self.view.bounds.size
65 |
66 | let topOffset :CGFloat = 55
67 | let vertGap :CGFloat = 15
68 | let horizGap :CGFloat = 25
69 | let wInput :CGFloat = 80
70 | var wOther :CGFloat = (cSize.width - (CGFloat(layers.count + 2) * horizGap) - wInput) / CGFloat(layers.count - 1)
71 | wOther = max(wOther, 265)
72 |
73 | var maxW :CGFloat = 0
74 | var maxH :CGFloat = 0
75 |
76 | var maxNumOfNeurons = 0
77 | for layer in layers {
78 | maxNumOfNeurons = max(maxNumOfNeurons, layer.count)
79 | }
80 | let h :CGFloat = max(123, 123 + 16 * CGFloat(maxNumOfNeurons - 4))
81 |
82 | for (layerIndex,layer) in layers.enumerated() {
83 |
84 | let w:CGFloat = layerIndex == 0 ? wInput : wOther
85 | let xPos = layerIndex == 0 ? horizGap : horizGap + CGFloat(layerIndex) * (horizGap + w) - (wOther - wInput)
86 |
87 |
88 | //Layer Label
89 | var layerLabelText = "Input"
90 | if (layerIndex == layers.count - 1) {
91 | layerLabelText = "Output"
92 | }
93 | else if (layerIndex == 0) {
94 | layerLabelText = "Input"
95 | }
96 | else {
97 | layerLabelText = "Hidden"
98 | }
99 | let llbFrame = CGRect(x: xPos, y: 25, width: 75, height: 25)
100 | let layerLabel = NeuronInputsView.makeLabel(f: llbFrame)
101 | layerLabel.text = layerLabelText
102 | layerLabel.textAlignment = .left
103 | layerLabel.textColor = UIColor.lightGray
104 | self.scrollView.addSubview(layerLabel)
105 |
106 |
107 | //Neuron Views
108 | for (neuronIndex,neuron) in layer.enumerated() {
109 |
110 | let nf = CGRect(x: xPos, y: topOffset + vertGap + CGFloat(neuronIndex) * (vertGap + h), width: w, height: h)
111 | let neuronView = NeuronInputsView(frame: nf)
112 | neuronView.idLabel.text = String(describing: neuron.identifier )
113 | self.scrollView.addSubview(neuronView)
114 |
115 | var theInputs = [InputA]()
116 | for key in neuron.inputs.keys {
117 | let val = neuron.inputs[key]!
118 | theInputs.append(val)
119 | }
120 | neuronView.buildInputs(inputs:theInputs)
121 |
122 | self.neuronViews[neuron.identifier] = neuronView
123 |
124 | if (neuronView.frame.maxX > maxW) {
125 | maxW = neuronView.frame.maxX
126 | }
127 | if (neuronView.frame.maxY > maxH) {
128 | maxH = neuronView.frame.maxY
129 | }
130 | }
131 | }
132 |
133 | let sz = CGSize(width: maxW + 20, height: maxH + 20)
134 | self.scrollView.contentSize = sz
135 |
136 | let numInputs = layers[0].count
137 | let numOutputs = layers[layers.count - 1].count
138 | let numHidden = layers.count - 2
139 |
140 | let inputStr = numInputs > 1 ? "Inputs" : "Input"
141 | let outputStr = numOutputs > 1 ? "Outputs" : "Output"
142 | let hiddenStr = numHidden > 1 ? "layers" : "layer"
143 | self.infoLabel.text = "\(numInputs) \(inputStr) and \(numOutputs) \(outputStr) | \(numHidden) Hidden \(hiddenStr)"
144 | self.learningRateLabel.text = String(describing: learningRate)
145 |
146 | }
147 |
148 |
149 |
150 | //MARK:- View Updating
151 |
152 |
153 |
154 | func updateNetworkView(layers:[[NeuronA]], percentComplete:CGFloat) {
155 |
156 | DispatchQueue.main.async { [weak self] in
157 | guard let theSelf = self else { return }
158 |
159 | for (_,layer) in layers.enumerated() {
160 | for (_,neuron) in layer.enumerated() {
161 | let neuronView = theSelf.neuronViews[neuron.identifier]!
162 | if neuron.inputs.count > 0 {
163 | for inputKey in neuron.inputs.keys {
164 | let inputLabel = neuronView.inputLabels[inputKey]
165 | let input = neuron.inputs[inputKey]!
166 |
167 | inputLabel?.text = inputKey + " : " + String(input.weight)
168 | if let theBias = neuron.bias {
169 | neuronView.biasLabel.text = "BIAS " + String(theBias)
170 | }
171 | }
172 | }
173 | else {
174 | //Input neuron
175 | }
176 | }
177 | }
178 |
179 | //Progress bar
180 | let progress = Float(percentComplete)
181 | theSelf.progressBar.setProgress(progress, animated: true)
182 | }
183 | }
184 |
185 |
186 |
187 | //MARK:- Output View
188 |
189 |
190 |
191 | func displayOutputView(inputs:[[Double]], outputs:[[Double]], layers:[[NeuronA]]) {
192 |
193 | if inputs.count != outputs.count { return }
194 |
195 | self.testInputs = inputs
196 | self.testOutputs = outputs
197 | self.testLayers = layers
198 |
199 | self.deployTestOutputView()
200 | }
201 |
202 |
203 | private func deployTestOutputView() {
204 |
205 | guard let theTestInputs = self.testInputs else { return }
206 | guard let theTestOutputs = self.testOutputs else { return }
207 | guard let theTestLayers = self.testLayers else { return }
208 |
209 | let storyboard = UIStoryboard(name: "Main", bundle: nil)
210 | let vc = storyboard.instantiateViewController(withIdentifier: "id_outputTable") as! OutputTableController
211 | vc.inputs = theTestInputs
212 | vc.outputs = theTestOutputs
213 | vc.layers = theTestLayers
214 |
215 | let navController = UINavigationController(rootViewController: vc)
216 |
217 | self.present(navController, animated: true) {
218 |
219 | self.progressBar.isHidden = true
220 | self.trainingProgressLabel.isHidden = true
221 | self.testInputsButton.isHidden = false
222 |
223 | }
224 |
225 | }
226 |
227 | @IBAction func testInputsButtonHandle(_ sender: AnyObject) {
228 |
229 | self.deployTestOutputView()
230 | }
231 |
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Network/NetworkA.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkA.swift
3 | // Simple-Swift-AI
4 | //
5 | // Created by Arjun Gupta on 7/29/16.
6 | // Copyright © 2016 ArjunGupta. All rights reserved.
7 | //
8 |
9 | import Accelerate
10 | import Foundation
11 | import UIKit
12 |
13 | class NetworkA {
14 |
15 | var learningRate :Double = 0.5
16 | var layers = [[NeuronA]]()
17 | private var networkVC :NetworkViewController?
18 | private var persistUtil :CoreDataUtil?
19 | private var persistanceID :String? = nil
20 |
21 |
22 | init(rootVC:UIViewController? = nil, persistanceID:String? = nil) {
23 | if let theRootVC = rootVC {
24 | self.networkVC = NetworkViewController.loadVC(rootVC:theRootVC)
25 | }
26 | if let _ = persistanceID {
27 | self.persistanceID = persistanceID
28 | self.persistUtil = CoreDataUtil()
29 | }
30 | }
31 |
32 |
33 | func insert(neuron:NeuronA, layerNum:Int) {
34 | if (self.layers.count <= layerNum) {
35 | while self.layers.count <= layerNum {
36 | let layer = [NeuronA]()
37 | self.layers.append(layer)
38 | }
39 | }
40 | self.layers[layerNum].append(neuron)
41 | }
42 |
43 |
44 | //Assign weights to begin
45 | func connectNeuronsWithRandomizedWeights() {
46 |
47 | //Check persisted weights
48 | var persistedWeights:[[[String:Double]]]?
49 | if let thePersistantUtil = self.persistUtil {
50 |
51 | if let thePersistedWeights = thePersistantUtil.fetchExistingWeights(persistanceID:self.persistanceID!) {
52 |
53 | func checkLayerCompatibility() -> Bool {
54 | var compatible = true
55 | if (self.layers.count != thePersistedWeights.count) {
56 | compatible = false
57 | }
58 | else {
59 | for (layerIndex, layer) in self.layers.enumerated() {
60 | if layer.count != thePersistedWeights[layerIndex].count {
61 | compatible = false
62 | break
63 | }
64 | }
65 | }
66 | return compatible
67 | }
68 |
69 | if (checkLayerCompatibility()) {
70 | DebugLog("Using persisted weights. Persistance ID : \(self.persistanceID)")
71 | persistedWeights = thePersistedWeights
72 | }
73 | }
74 | }
75 |
76 | for (index,neuronLayer) in self.layers.enumerated() {
77 |
78 | if index == 0 { continue }
79 |
80 | for (nIndex,neuron) in neuronLayer.enumerated() {
81 | var neuronInputs = [InputA]()
82 |
83 |
84 | for (prevNeuronIndex,prevNeuron) in self.layers[index-1].enumerated() {
85 |
86 | var inputWt:Double?
87 |
88 | if let thePersistedWeights = persistedWeights {
89 | inputWt = thePersistedWeights[index][nIndex][prevNeuron.identifier]
90 | }
91 |
92 | if (inputWt == nil) {
93 | //DebugLog("Random assigned weights for : \(neuron.identifier) -->")
94 | let randomWeight:Double = Double(arc4random_uniform(15) + 45) * 0.01
95 | inputWt = randomWeight
96 | }
97 |
98 | let input = InputA(neuron: prevNeuron, weight: inputWt!)
99 | input.indexInLayer = prevNeuronIndex
100 | //DebugLog("\(input.neuron?.identifier) : \(randomWeight)")
101 |
102 | neuronInputs.append(input)
103 | }
104 | neuron.attachInputs(inputs: neuronInputs)
105 | }
106 | }
107 |
108 | self.networkVC?.buildView(layers: self.layers, learningRate: CGFloat(self.learningRate))
109 | }
110 |
111 |
112 | func checkCompatibility(input:[Double],output:[Double]?) -> Bool {
113 | //Fail safe check
114 |
115 | var trainingSetCompatible = true
116 | if (input.count != self.layers[0].count) {
117 | DebugLog("ERROR: Input neuron count mismatch with training inputs. Expected \(self.layers[0].count). Got \(input.count)")
118 | trainingSetCompatible = false
119 | }
120 | if let theOutput = output {
121 | if (theOutput.count != self.layers.last!.count) {
122 | DebugLog("ERROR: Out neuron count mismatch with training outputs. Expected \(self.layers.last!.count) Got \(theOutput.count)")
123 | trainingSetCompatible = false
124 | }
125 | }
126 | return trainingSetCompatible
127 | }
128 |
129 |
130 |
131 | func trainNetwork(trainingSets:[(input:[Double],output:[Double])], completionBlock: ((Bool,CGFloat) -> Void)?) {
132 |
133 | DispatchQueue.global(qos: .userInitiated).async { [weak self] in
134 |
135 | guard let theSelf = self else {
136 | DebugLog("ERROR: Self cannot be nil!")
137 | return
138 | }
139 |
140 | var currentPercentCompletion:CGFloat = 0
141 |
142 | for (ioSetIndex, ioSet) in trainingSets.enumerated() {
143 |
144 | if (theSelf.checkCompatibility(input:ioSet.input, output:ioSet.output) == false) { break }
145 |
146 | ///////DebugLog("setIndex : \(setIndex)")
147 |
148 | //MARK:- Forward pass
149 | for (layerIndex,layer) in theSelf.layers.enumerated() {
150 |
151 | for (neuronIndex,neuron) in layer.enumerated() {
152 | if (layerIndex == 0) {
153 | neuron.output = ioSet.input[neuronIndex]
154 | }
155 | else {
156 | neuron.calculateOutput()
157 | }
158 | }
159 | }
160 |
161 |
162 | //MARK:- Output error
163 | /*
164 | var totalError:Double = 0
165 | for (setIndex,targetOutput) in ioSet.output.enumerated() {
166 |
167 | let outputLayerNeurons = theSelf.layers.last!
168 | let outputNeuron = outputLayerNeurons[setIndex]
169 | let outputError = 0.5 * pow((targetOutput - outputNeuron.output!), 2)
170 | totalError += outputError
171 |
172 | //DebugLog("\(outputNeuron.identifier) output:\(outputNeuron.output!) expOutput:\(targetOutput), error : \(outputError)")
173 | }
174 | DebugLog("TotalError : \(totalError.roundToDigits(digits: 5))")
175 | */
176 |
177 |
178 | //MARK:- Backward pass
179 | var newWeights = [NeuronA:[(String,Double)]]()
180 | var layersErrorOByNetO = [[NeuronA:Double]]()
181 | var currentLayerCount = 0
182 |
183 | for i in stride(from: theSelf.layers.count - 1, through: 1, by: -1) {
184 |
185 | var aLayerErrorOByNetO = [NeuronA:Double]()
186 | let alayer = theSelf.layers[i]
187 | for (neuronIndex, aNeuron) in alayer.enumerated() {
188 |
189 | var newInputWeights = [(String,Double)]()
190 |
191 | var deltaO:Double = 0
192 | if (i == theSelf.layers.count - 1) { //Output layer
193 | let targetOutput = ioSet.output[neuronIndex]
194 | let deltaErrorByNet = -(targetOutput - aNeuron.output!) * aNeuron.output! * (1 - aNeuron.output!)
195 | aLayerErrorOByNetO[aNeuron] = deltaErrorByNet
196 | deltaO = deltaErrorByNet
197 | }
198 | else {
199 | var deltaErrorOByNetO:Double = 0
200 | let theLayerSigmaOutputs = layersErrorOByNetO[currentLayerCount - 1]
201 | for outputNeuron in theLayerSigmaOutputs.keys {
202 |
203 | let connectedInput = outputNeuron.inputs[aNeuron.identifier]!
204 | deltaErrorOByNetO += theLayerSigmaOutputs[outputNeuron]! * connectedInput.weight
205 |
206 | }
207 |
208 | //Store this in an array for use in deeper layers
209 | aLayerErrorOByNetO[aNeuron] = deltaErrorOByNetO
210 |
211 | deltaErrorOByNetO = deltaErrorOByNetO * aNeuron.output!*(1 - aNeuron.output!)
212 |
213 | deltaO = deltaErrorOByNetO
214 | }
215 |
216 | for input in aNeuron.inputs.values {
217 |
218 |
219 | let dTotalError_by_dOutputWeight = deltaO * input.value!
220 |
221 | let newWeight = input.weight - (theSelf.learningRate * dTotalError_by_dOutputWeight)
222 |
223 | //DebugLog("\(aNeuron.identifier) newWeight\(input.neuron?.identifier) : \(newWeight)")
224 |
225 | let inputWtDict = (input.neuron!.identifier,newWeight)
226 | newInputWeights.append(inputWtDict)
227 | }
228 | newWeights[aNeuron] = newInputWeights
229 | }
230 |
231 | layersErrorOByNetO.append(aLayerErrorOByNetO)
232 | currentLayerCount += 1
233 | }
234 |
235 | for aNeuron in newWeights.keys {
236 |
237 | let newNeuronInputWeights = newWeights[aNeuron]
238 | for tp in newNeuronInputWeights! {
239 | aNeuron.inputs[tp.0]!.weight = tp.1
240 | }
241 | }
242 |
243 | //Completion block
244 | let cutOff:CGFloat = 0.005 //Reducing number of UI updates
245 | let percentComplete = CGFloat(ioSetIndex) / CGFloat(trainingSets.count)
246 | if (percentComplete - currentPercentCompletion > cutOff || percentComplete > 0.99) {
247 | currentPercentCompletion += cutOff
248 |
249 | theSelf.networkVC?.updateNetworkView(layers: theSelf.layers, percentComplete:percentComplete)
250 |
251 | //DispatchQueue.main.async {
252 | // completionBlock!(false, percentComplete)
253 | //}
254 | }
255 | }
256 |
257 |
258 | DispatchQueue.main.async {
259 |
260 | theSelf.persistUtil?.persistNewWeights(neurons: theSelf.layers, persistanceID: theSelf.persistanceID!)
261 |
262 | completionBlock!(true, 100.0)
263 | }
264 | }
265 |
266 | }
267 |
268 |
269 | //Use this for testing the FFNN after the training
270 |
271 |
272 | func getOutputFor(inputs:[[Double]]) -> [[Double]] {
273 |
274 | var outputs = [[Double]]()
275 |
276 | for (inputIndex,inputSet) in inputs.enumerated() {
277 |
278 | DebugLog("^^^ Test result \(inputIndex)-->")
279 |
280 | if (self.checkCompatibility(input:inputSet, output:nil) == false) { break }
281 |
282 | var output = [Double]()
283 |
284 | for (index,layer) in self.layers.enumerated() {
285 |
286 | if index == 0 {
287 | for (neuronIndex,neuron) in layer.enumerated() {
288 | neuron.output = inputSet[neuronIndex]
289 | neuron.calculateOutput()
290 | }
291 | }
292 | else {
293 | for neuron in layer {
294 | neuron.calculateOutput()
295 | if (index == self.layers.count - 1) {
296 | DebugLog("\(neuron.identifier) output : \(neuron.output)")
297 |
298 | output.append(neuron.output!)
299 | }
300 | }
301 | }
302 | }
303 |
304 | outputs.append(output)
305 |
306 | DebugLog("--------")
307 | }
308 |
309 | self.networkVC?.displayOutputView(inputs: inputs, outputs: outputs, layers:self.layers)
310 |
311 | return outputs
312 | }
313 |
314 |
315 | }
316 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 67B9AF981D9F030C0058E2BA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AF971D9F030C0058E2BA /* AppDelegate.swift */; };
11 | 67B9AF9A1D9F030C0058E2BA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AF991D9F030C0058E2BA /* ViewController.swift */; };
12 | 67B9AF9D1D9F030C0058E2BA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67B9AF9B1D9F030C0058E2BA /* Main.storyboard */; };
13 | 67B9AFA01D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AF9E1D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodeld */; };
14 | 67B9AFA21D9F030C0058E2BA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 67B9AFA11D9F030C0058E2BA /* Assets.xcassets */; };
15 | 67B9AFA51D9F030C0058E2BA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67B9AFA31D9F030C0058E2BA /* LaunchScreen.storyboard */; };
16 | 67B9AFB91D9F03990058E2BA /* ActivationFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFAD1D9F03990058E2BA /* ActivationFunctions.swift */; };
17 | 67B9AFBA1D9F03990058E2BA /* AutoNetworkBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFAE1D9F03990058E2BA /* AutoNetworkBuilder.swift */; };
18 | 67B9AFBB1D9F03990058E2BA /* InputA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFAF1D9F03990058E2BA /* InputA.swift */; };
19 | 67B9AFBC1D9F03990058E2BA /* NetworkA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFB01D9F03990058E2BA /* NetworkA.swift */; };
20 | 67B9AFBD1D9F03990058E2BA /* NeuronA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFB11D9F03990058E2BA /* NeuronA.swift */; };
21 | 67B9AFC01D9F03990058E2BA /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFB81D9F03990058E2BA /* Utils.swift */; };
22 | 67B9AFC31D9F03DE0058E2BA /* AI_System_XOR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFC21D9F03DE0058E2BA /* AI_System_XOR.swift */; };
23 | 67B9AFC91D9F042B0058E2BA /* NetworkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFC51D9F042B0058E2BA /* NetworkViewController.swift */; };
24 | 67B9AFCA1D9F042B0058E2BA /* NeuronInputsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFC61D9F042B0058E2BA /* NeuronInputsView.swift */; };
25 | 67B9AFCB1D9F042B0058E2BA /* OutputTableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFC71D9F042B0058E2BA /* OutputTableController.swift */; };
26 | 67B9AFCC1D9F042B0058E2BA /* OutputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFC81D9F042B0058E2BA /* OutputTableViewCell.swift */; };
27 | 67B9AFEF1DA1EF410058E2BA /* CoreDataUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B9AFEE1DA1EF410058E2BA /* CoreDataUtil.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXFileReference section */
31 | 67B9AF941D9F030C0058E2BA /* Simple-Swift-AI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Simple-Swift-AI.app"; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 67B9AF971D9F030C0058E2BA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
33 | 67B9AF991D9F030C0058E2BA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
34 | 67B9AF9C1D9F030C0058E2BA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
35 | 67B9AF9F1D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Simple_Swift_AI.xcdatamodel; sourceTree = ""; };
36 | 67B9AFA11D9F030C0058E2BA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
37 | 67B9AFA41D9F030C0058E2BA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
38 | 67B9AFA61D9F030C0058E2BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
39 | 67B9AFAD1D9F03990058E2BA /* ActivationFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivationFunctions.swift; sourceTree = ""; };
40 | 67B9AFAE1D9F03990058E2BA /* AutoNetworkBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoNetworkBuilder.swift; sourceTree = ""; };
41 | 67B9AFAF1D9F03990058E2BA /* InputA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputA.swift; sourceTree = ""; };
42 | 67B9AFB01D9F03990058E2BA /* NetworkA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkA.swift; sourceTree = ""; };
43 | 67B9AFB11D9F03990058E2BA /* NeuronA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeuronA.swift; sourceTree = ""; };
44 | 67B9AFB81D9F03990058E2BA /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
45 | 67B9AFC21D9F03DE0058E2BA /* AI_System_XOR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AI_System_XOR.swift; sourceTree = ""; };
46 | 67B9AFC51D9F042B0058E2BA /* NetworkViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkViewController.swift; sourceTree = ""; };
47 | 67B9AFC61D9F042B0058E2BA /* NeuronInputsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeuronInputsView.swift; sourceTree = ""; };
48 | 67B9AFC71D9F042B0058E2BA /* OutputTableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutputTableController.swift; sourceTree = ""; };
49 | 67B9AFC81D9F042B0058E2BA /* OutputTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutputTableViewCell.swift; sourceTree = ""; };
50 | 67B9AFEE1DA1EF410058E2BA /* CoreDataUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoreDataUtil.swift; path = ../Utils/CoreDataUtil.swift; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | 67B9AF911D9F030C0058E2BA /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 67B9AF8B1D9F030C0058E2BA = {
65 | isa = PBXGroup;
66 | children = (
67 | 67B9AF961D9F030C0058E2BA /* Simple-Swift-AI */,
68 | 67B9AF951D9F030C0058E2BA /* Products */,
69 | );
70 | sourceTree = "";
71 | };
72 | 67B9AF951D9F030C0058E2BA /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 67B9AF941D9F030C0058E2BA /* Simple-Swift-AI.app */,
76 | );
77 | name = Products;
78 | sourceTree = "";
79 | };
80 | 67B9AF961D9F030C0058E2BA /* Simple-Swift-AI */ = {
81 | isa = PBXGroup;
82 | children = (
83 | 67B9AF971D9F030C0058E2BA /* AppDelegate.swift */,
84 | 67B9AF991D9F030C0058E2BA /* ViewController.swift */,
85 | 67B9AFC11D9F03DE0058E2BA /* Examples */,
86 | 67B9AFAC1D9F03990058E2BA /* Network */,
87 | 67B9AFC41D9F042B0058E2BA /* DebugView */,
88 | 67B9AFF01DA1FADF0058E2BA /* Persistance */,
89 | 67B9AFB71D9F03990058E2BA /* Utils */,
90 | 67B9AF9B1D9F030C0058E2BA /* Main.storyboard */,
91 | 67B9AFA11D9F030C0058E2BA /* Assets.xcassets */,
92 | 67B9AFA31D9F030C0058E2BA /* LaunchScreen.storyboard */,
93 | 67B9AFA61D9F030C0058E2BA /* Info.plist */,
94 | 67B9AF9E1D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodeld */,
95 | );
96 | path = "Simple-Swift-AI";
97 | sourceTree = "";
98 | };
99 | 67B9AFAC1D9F03990058E2BA /* Network */ = {
100 | isa = PBXGroup;
101 | children = (
102 | 67B9AFAE1D9F03990058E2BA /* AutoNetworkBuilder.swift */,
103 | 67B9AFB01D9F03990058E2BA /* NetworkA.swift */,
104 | 67B9AFAF1D9F03990058E2BA /* InputA.swift */,
105 | 67B9AFB11D9F03990058E2BA /* NeuronA.swift */,
106 | 67B9AFAD1D9F03990058E2BA /* ActivationFunctions.swift */,
107 | );
108 | path = Network;
109 | sourceTree = "";
110 | };
111 | 67B9AFB71D9F03990058E2BA /* Utils */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 67B9AFB81D9F03990058E2BA /* Utils.swift */,
115 | );
116 | path = Utils;
117 | sourceTree = "";
118 | };
119 | 67B9AFC11D9F03DE0058E2BA /* Examples */ = {
120 | isa = PBXGroup;
121 | children = (
122 | 67B9AFC21D9F03DE0058E2BA /* AI_System_XOR.swift */,
123 | );
124 | path = Examples;
125 | sourceTree = "";
126 | };
127 | 67B9AFC41D9F042B0058E2BA /* DebugView */ = {
128 | isa = PBXGroup;
129 | children = (
130 | 67B9AFC51D9F042B0058E2BA /* NetworkViewController.swift */,
131 | 67B9AFC61D9F042B0058E2BA /* NeuronInputsView.swift */,
132 | 67B9AFC71D9F042B0058E2BA /* OutputTableController.swift */,
133 | 67B9AFC81D9F042B0058E2BA /* OutputTableViewCell.swift */,
134 | );
135 | path = DebugView;
136 | sourceTree = "";
137 | };
138 | 67B9AFF01DA1FADF0058E2BA /* Persistance */ = {
139 | isa = PBXGroup;
140 | children = (
141 | 67B9AFEE1DA1EF410058E2BA /* CoreDataUtil.swift */,
142 | );
143 | name = Persistance;
144 | path = DebugView;
145 | sourceTree = "";
146 | };
147 | /* End PBXGroup section */
148 |
149 | /* Begin PBXNativeTarget section */
150 | 67B9AF931D9F030C0058E2BA /* Simple-Swift-AI */ = {
151 | isa = PBXNativeTarget;
152 | buildConfigurationList = 67B9AFA91D9F030C0058E2BA /* Build configuration list for PBXNativeTarget "Simple-Swift-AI" */;
153 | buildPhases = (
154 | 67B9AF901D9F030C0058E2BA /* Sources */,
155 | 67B9AF911D9F030C0058E2BA /* Frameworks */,
156 | 67B9AF921D9F030C0058E2BA /* Resources */,
157 | );
158 | buildRules = (
159 | );
160 | dependencies = (
161 | );
162 | name = "Simple-Swift-AI";
163 | productName = "Simple-Swift-AI";
164 | productReference = 67B9AF941D9F030C0058E2BA /* Simple-Swift-AI.app */;
165 | productType = "com.apple.product-type.application";
166 | };
167 | /* End PBXNativeTarget section */
168 |
169 | /* Begin PBXProject section */
170 | 67B9AF8C1D9F030C0058E2BA /* Project object */ = {
171 | isa = PBXProject;
172 | attributes = {
173 | LastSwiftUpdateCheck = 0800;
174 | LastUpgradeCheck = 0800;
175 | ORGANIZATIONNAME = "Arjun Gupta";
176 | TargetAttributes = {
177 | 67B9AF931D9F030C0058E2BA = {
178 | CreatedOnToolsVersion = 8.0;
179 | DevelopmentTeam = W9K648WB82;
180 | ProvisioningStyle = Automatic;
181 | };
182 | };
183 | };
184 | buildConfigurationList = 67B9AF8F1D9F030C0058E2BA /* Build configuration list for PBXProject "Simple-Swift-AI" */;
185 | compatibilityVersion = "Xcode 3.2";
186 | developmentRegion = English;
187 | hasScannedForEncodings = 0;
188 | knownRegions = (
189 | en,
190 | Base,
191 | );
192 | mainGroup = 67B9AF8B1D9F030C0058E2BA;
193 | productRefGroup = 67B9AF951D9F030C0058E2BA /* Products */;
194 | projectDirPath = "";
195 | projectRoot = "";
196 | targets = (
197 | 67B9AF931D9F030C0058E2BA /* Simple-Swift-AI */,
198 | );
199 | };
200 | /* End PBXProject section */
201 |
202 | /* Begin PBXResourcesBuildPhase section */
203 | 67B9AF921D9F030C0058E2BA /* Resources */ = {
204 | isa = PBXResourcesBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | 67B9AFA51D9F030C0058E2BA /* LaunchScreen.storyboard in Resources */,
208 | 67B9AFA21D9F030C0058E2BA /* Assets.xcassets in Resources */,
209 | 67B9AF9D1D9F030C0058E2BA /* Main.storyboard in Resources */,
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | };
213 | /* End PBXResourcesBuildPhase section */
214 |
215 | /* Begin PBXSourcesBuildPhase section */
216 | 67B9AF901D9F030C0058E2BA /* Sources */ = {
217 | isa = PBXSourcesBuildPhase;
218 | buildActionMask = 2147483647;
219 | files = (
220 | 67B9AFEF1DA1EF410058E2BA /* CoreDataUtil.swift in Sources */,
221 | 67B9AFBD1D9F03990058E2BA /* NeuronA.swift in Sources */,
222 | 67B9AF9A1D9F030C0058E2BA /* ViewController.swift in Sources */,
223 | 67B9AFC91D9F042B0058E2BA /* NetworkViewController.swift in Sources */,
224 | 67B9AF981D9F030C0058E2BA /* AppDelegate.swift in Sources */,
225 | 67B9AFBC1D9F03990058E2BA /* NetworkA.swift in Sources */,
226 | 67B9AFC01D9F03990058E2BA /* Utils.swift in Sources */,
227 | 67B9AFBB1D9F03990058E2BA /* InputA.swift in Sources */,
228 | 67B9AFC31D9F03DE0058E2BA /* AI_System_XOR.swift in Sources */,
229 | 67B9AFA01D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodeld in Sources */,
230 | 67B9AFBA1D9F03990058E2BA /* AutoNetworkBuilder.swift in Sources */,
231 | 67B9AFCA1D9F042B0058E2BA /* NeuronInputsView.swift in Sources */,
232 | 67B9AFCB1D9F042B0058E2BA /* OutputTableController.swift in Sources */,
233 | 67B9AFCC1D9F042B0058E2BA /* OutputTableViewCell.swift in Sources */,
234 | 67B9AFB91D9F03990058E2BA /* ActivationFunctions.swift in Sources */,
235 | );
236 | runOnlyForDeploymentPostprocessing = 0;
237 | };
238 | /* End PBXSourcesBuildPhase section */
239 |
240 | /* Begin PBXVariantGroup section */
241 | 67B9AF9B1D9F030C0058E2BA /* Main.storyboard */ = {
242 | isa = PBXVariantGroup;
243 | children = (
244 | 67B9AF9C1D9F030C0058E2BA /* Base */,
245 | );
246 | name = Main.storyboard;
247 | sourceTree = "";
248 | };
249 | 67B9AFA31D9F030C0058E2BA /* LaunchScreen.storyboard */ = {
250 | isa = PBXVariantGroup;
251 | children = (
252 | 67B9AFA41D9F030C0058E2BA /* Base */,
253 | );
254 | name = LaunchScreen.storyboard;
255 | sourceTree = "";
256 | };
257 | /* End PBXVariantGroup section */
258 |
259 | /* Begin XCBuildConfiguration section */
260 | 67B9AFA71D9F030C0058E2BA /* Debug */ = {
261 | isa = XCBuildConfiguration;
262 | buildSettings = {
263 | ALWAYS_SEARCH_USER_PATHS = NO;
264 | CLANG_ANALYZER_NONNULL = YES;
265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
266 | CLANG_CXX_LIBRARY = "libc++";
267 | CLANG_ENABLE_MODULES = YES;
268 | CLANG_ENABLE_OBJC_ARC = YES;
269 | CLANG_WARN_BOOL_CONVERSION = YES;
270 | CLANG_WARN_CONSTANT_CONVERSION = YES;
271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
272 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
273 | CLANG_WARN_EMPTY_BODY = YES;
274 | CLANG_WARN_ENUM_CONVERSION = YES;
275 | CLANG_WARN_INFINITE_RECURSION = YES;
276 | CLANG_WARN_INT_CONVERSION = YES;
277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
278 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
279 | CLANG_WARN_UNREACHABLE_CODE = YES;
280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
281 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
282 | COPY_PHASE_STRIP = NO;
283 | DEBUG_INFORMATION_FORMAT = dwarf;
284 | ENABLE_STRICT_OBJC_MSGSEND = YES;
285 | ENABLE_TESTABILITY = YES;
286 | GCC_C_LANGUAGE_STANDARD = gnu99;
287 | GCC_DYNAMIC_NO_PIC = NO;
288 | GCC_NO_COMMON_BLOCKS = YES;
289 | GCC_OPTIMIZATION_LEVEL = 0;
290 | GCC_PREPROCESSOR_DEFINITIONS = (
291 | "DEBUG=1",
292 | "$(inherited)",
293 | );
294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
296 | GCC_WARN_UNDECLARED_SELECTOR = YES;
297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
298 | GCC_WARN_UNUSED_FUNCTION = YES;
299 | GCC_WARN_UNUSED_VARIABLE = YES;
300 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
301 | MTL_ENABLE_DEBUG_INFO = YES;
302 | ONLY_ACTIVE_ARCH = YES;
303 | SDKROOT = iphoneos;
304 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
305 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
306 | TARGETED_DEVICE_FAMILY = "1,2";
307 | };
308 | name = Debug;
309 | };
310 | 67B9AFA81D9F030C0058E2BA /* Release */ = {
311 | isa = XCBuildConfiguration;
312 | buildSettings = {
313 | ALWAYS_SEARCH_USER_PATHS = NO;
314 | CLANG_ANALYZER_NONNULL = YES;
315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
316 | CLANG_CXX_LIBRARY = "libc++";
317 | CLANG_ENABLE_MODULES = YES;
318 | CLANG_ENABLE_OBJC_ARC = YES;
319 | CLANG_WARN_BOOL_CONVERSION = YES;
320 | CLANG_WARN_CONSTANT_CONVERSION = YES;
321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
322 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
323 | CLANG_WARN_EMPTY_BODY = YES;
324 | CLANG_WARN_ENUM_CONVERSION = YES;
325 | CLANG_WARN_INFINITE_RECURSION = YES;
326 | CLANG_WARN_INT_CONVERSION = YES;
327 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
328 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
329 | CLANG_WARN_UNREACHABLE_CODE = YES;
330 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
331 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
332 | COPY_PHASE_STRIP = NO;
333 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
334 | ENABLE_NS_ASSERTIONS = NO;
335 | ENABLE_STRICT_OBJC_MSGSEND = YES;
336 | GCC_C_LANGUAGE_STANDARD = gnu99;
337 | GCC_NO_COMMON_BLOCKS = YES;
338 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
339 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
340 | GCC_WARN_UNDECLARED_SELECTOR = YES;
341 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
342 | GCC_WARN_UNUSED_FUNCTION = YES;
343 | GCC_WARN_UNUSED_VARIABLE = YES;
344 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
345 | MTL_ENABLE_DEBUG_INFO = NO;
346 | SDKROOT = iphoneos;
347 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
348 | TARGETED_DEVICE_FAMILY = "1,2";
349 | VALIDATE_PRODUCT = YES;
350 | };
351 | name = Release;
352 | };
353 | 67B9AFAA1D9F030C0058E2BA /* Debug */ = {
354 | isa = XCBuildConfiguration;
355 | buildSettings = {
356 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
358 | DEVELOPMENT_TEAM = W9K648WB82;
359 | INFOPLIST_FILE = "Simple-Swift-AI/Info.plist";
360 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
361 | PRODUCT_BUNDLE_IDENTIFIER = "Arjun-Gupta.Simple-Swift-AI";
362 | PRODUCT_NAME = "$(TARGET_NAME)";
363 | SWIFT_VERSION = 3.0;
364 | };
365 | name = Debug;
366 | };
367 | 67B9AFAB1D9F030C0058E2BA /* Release */ = {
368 | isa = XCBuildConfiguration;
369 | buildSettings = {
370 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
371 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
372 | DEVELOPMENT_TEAM = W9K648WB82;
373 | INFOPLIST_FILE = "Simple-Swift-AI/Info.plist";
374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
375 | PRODUCT_BUNDLE_IDENTIFIER = "Arjun-Gupta.Simple-Swift-AI";
376 | PRODUCT_NAME = "$(TARGET_NAME)";
377 | SWIFT_VERSION = 3.0;
378 | };
379 | name = Release;
380 | };
381 | /* End XCBuildConfiguration section */
382 |
383 | /* Begin XCConfigurationList section */
384 | 67B9AF8F1D9F030C0058E2BA /* Build configuration list for PBXProject "Simple-Swift-AI" */ = {
385 | isa = XCConfigurationList;
386 | buildConfigurations = (
387 | 67B9AFA71D9F030C0058E2BA /* Debug */,
388 | 67B9AFA81D9F030C0058E2BA /* Release */,
389 | );
390 | defaultConfigurationIsVisible = 0;
391 | defaultConfigurationName = Release;
392 | };
393 | 67B9AFA91D9F030C0058E2BA /* Build configuration list for PBXNativeTarget "Simple-Swift-AI" */ = {
394 | isa = XCConfigurationList;
395 | buildConfigurations = (
396 | 67B9AFAA1D9F030C0058E2BA /* Debug */,
397 | 67B9AFAB1D9F030C0058E2BA /* Release */,
398 | );
399 | defaultConfigurationIsVisible = 0;
400 | defaultConfigurationName = Release;
401 | };
402 | /* End XCConfigurationList section */
403 |
404 | /* Begin XCVersionGroup section */
405 | 67B9AF9E1D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodeld */ = {
406 | isa = XCVersionGroup;
407 | children = (
408 | 67B9AF9F1D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodel */,
409 | );
410 | currentVersion = 67B9AF9F1D9F030C0058E2BA /* Simple_Swift_AI.xcdatamodel */;
411 | path = Simple_Swift_AI.xcdatamodeld;
412 | sourceTree = "";
413 | versionGroupType = wrapper.xcdatamodel;
414 | };
415 | /* End XCVersionGroup section */
416 | };
417 | rootObject = 67B9AF8C1D9F030C0058E2BA /* Project object */;
418 | }
419 |
--------------------------------------------------------------------------------
/Simple-Swift-AI/Simple-Swift-AI/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
74 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
215 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
245 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
--------------------------------------------------------------------------------