From 76cce575a76ca496e772bbb7a873521c1bb23076 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Wed, 21 Nov 2018 17:25:40 +0900 Subject: [PATCH 1/9] :+1: Fix exp #122 --- .../1968/Brown&Jenkins(1968).swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift b/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift index 26a48d1..7a01ea3 100644 --- a/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift +++ b/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift @@ -17,13 +17,15 @@ class BrownAndJenkins1968 { let numberOfPairings: Int = 80 let whiteKeyLightDuration: Seconds = 8 let trayOperatingDuration: Milliseconds = 4000 - let interTrialInterval: [Seconds] = [Seconds](30...90).filter({ $0 % 5 == 0 }) + let interTrialInterval: [Seconds] = [Seconds](30...90) + .filter({ $0 % 5 == 0 }) + .map { TimeUnit.seconds.milliseconds($0) } + .shuffled() var nextInterval: Milliseconds = 0 + var currentOrder: Int = 0 func updateInterval() { - nextInterval = TimeUnit.seconds.milliseconds( - interTrialInterval[Seconds.random(in: 0.. Date: Thu, 22 Nov 2018 10:50:53 +0900 Subject: [PATCH 2/9] :+1: Improve UX #122 --- OperantKit.xcodeproj/project.pbxproj | 10 ++++++++++ .../Extensions/ObservableType+.swift | 18 ++++++++++++++++++ .../Extensions/PublishSubject+.swift | 16 ++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 Sources/Application/Extensions/PublishSubject+.swift diff --git a/OperantKit.xcodeproj/project.pbxproj b/OperantKit.xcodeproj/project.pbxproj index 8f94c2a..cb533c1 100644 --- a/OperantKit.xcodeproj/project.pbxproj +++ b/OperantKit.xcodeproj/project.pbxproj @@ -10,6 +10,10 @@ 99334342212969BA00744042 /* OperantKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 99334339212969B900744042 /* OperantKit.framework */; }; 9933435E212969E000744042 /* OperantKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 99334355212969E000744042 /* OperantKit.framework */; }; 9965649F21A4FBCA004C76F0 /* ObservableMilliseconds+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965649E21A4FBCA004C76F0 /* ObservableMilliseconds+.swift */; }; + 996564D221A63E39004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; + 996564D321A63E3D004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; + 996564D421A63E3D004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; + 996564D521A63E3E004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; 9998170D212C355900D9F6E5 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170B212C355900D9F6E5 /* RxCocoa.framework */; }; 9998170E212C355900D9F6E5 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170C212C355900D9F6E5 /* RxSwift.framework */; }; 99981711212C356E00D9F6E5 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170F212C356E00D9F6E5 /* RxSwift.framework */; }; @@ -391,6 +395,7 @@ 9933437E21296A9A00744042 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 994FFF5D212C2918000F4702 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = ""; }; 9965649E21A4FBCA004C76F0 /* ObservableMilliseconds+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObservableMilliseconds+.swift"; sourceTree = ""; }; + 996564D121A63E39004C76F0 /* PublishSubject+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublishSubject+.swift"; sourceTree = ""; }; 9998170B212C355900D9F6E5 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/Mac/RxCocoa.framework; sourceTree = ""; }; 9998170C212C355900D9F6E5 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/Mac/RxSwift.framework; sourceTree = ""; }; 9998170F212C356E00D9F6E5 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; @@ -873,6 +878,7 @@ 999C7C9E21951CDB0044C47E /* Observable+.swift */, 9965649E21A4FBCA004C76F0 /* ObservableMilliseconds+.swift */, 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */, + 996564D121A63E39004C76F0 /* PublishSubject+.swift */, ); name = Rx; sourceTree = ""; @@ -1357,6 +1363,7 @@ 999C7CC121951CDB0044C47E /* PrepositionSchedule.swift in Sources */, 99C751B521A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530321A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 996564D321A63E3D004C76F0 /* PublishSubject+.swift in Sources */, 999C7D3021951CDC0044C47E /* Shared.swift in Sources */, 99C751B021A0949A00DABE14 /* Loggable.swift in Sources */, 999C7D0021951CDC0044C47E /* ResponseEntity.swift in Sources */, @@ -1441,6 +1448,7 @@ 999C7CC521951CDB0044C47E /* PostpositionSchedule.swift in Sources */, 999C7CB021951CDB0044C47E /* FI.swift in Sources */, 99C752F821A2C66A00DABE14 /* UInt64+.swift in Sources */, + 996564D221A63E39004C76F0 /* PublishSubject+.swift in Sources */, 99C74EF6219A70F100DABE14 /* VT.swift in Sources */, 99C751A021A08C3300DABE14 /* Concurrentable.swift in Sources */, 99C7518021A06ED100DABE14 /* ScheduleUseCase+.swift in Sources */, @@ -1556,6 +1564,7 @@ 999C7DA8219533150044C47E /* PrepositionSchedule.swift in Sources */, 99C751B621A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530421A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 996564D421A63E3D004C76F0 /* PublishSubject+.swift in Sources */, 999C7DA9219533150044C47E /* PostpositionSchedule.swift in Sources */, 99C751B121A0949A00DABE14 /* Loggable.swift in Sources */, 999C7DAA219533150044C47E /* SessionEvents.swift in Sources */, @@ -1655,6 +1664,7 @@ 999C7DFC219542610044C47E /* PrepositionSchedule.swift in Sources */, 99C751B721A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530521A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 996564D521A63E3E004C76F0 /* PublishSubject+.swift in Sources */, 999C7DFD219542610044C47E /* PostpositionSchedule.swift in Sources */, 99C751B221A0949A00DABE14 /* Loggable.swift in Sources */, 999C7DFE219542610044C47E /* SessionEvents.swift in Sources */, diff --git a/Sources/Application/Extensions/ObservableType+.swift b/Sources/Application/Extensions/ObservableType+.swift index 370c80b..4c57369 100644 --- a/Sources/Application/Extensions/ObservableType+.swift +++ b/Sources/Application/Extensions/ObservableType+.swift @@ -23,3 +23,21 @@ public extension ObservableType { } } } + +public extension ObservableType { + /// Count up + func count() -> Observable { + return scan(0) { n, _ in n + 1 } + } + + /// Get time + func getTime(_ timer: TimerUseCase) -> Observable { + return flatMap { _ in timer.elapsed() } + } + + /// Response entity + func response(_ timer: TimerUseCase) -> Observable { + return Observable.zip(count(), getTime(timer)) + .map { ResponseEntity(numOfResponses: $0.0, milliseconds: $0.1) } + } +} diff --git a/Sources/Application/Extensions/PublishSubject+.swift b/Sources/Application/Extensions/PublishSubject+.swift new file mode 100644 index 0000000..99910cc --- /dev/null +++ b/Sources/Application/Extensions/PublishSubject+.swift @@ -0,0 +1,16 @@ +// +// PublishSubject+.swift +// OperantKit macOS +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import RxSwift + +public extension PublishSubject where E == Milliseconds { + /// Optimized time + var shared: Observable { + return distinctUntilChanged() + .share(replay: 1) + } +} From fac068df0cce9931e1c434f193c49a9274412d19 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Thu, 22 Nov 2018 12:17:15 +0900 Subject: [PATCH 3/9] :+1: Add init #122 --- Sources/Application/Helpers/Matrix.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Application/Helpers/Matrix.swift b/Sources/Application/Helpers/Matrix.swift index 3df96cd..6f6cedd 100644 --- a/Sources/Application/Helpers/Matrix.swift +++ b/Sources/Application/Helpers/Matrix.swift @@ -12,20 +12,20 @@ public struct Matrix { public let rows: Int public let columns: Int - public init(elements: [Element], rows: Int, columns: Int) { + public init(_ elements: [Element], rows: Int, columns: Int) { self.elements = elements self.rows = rows self.columns = columns } - public init?(elements: [Element], rows: Int) { + public init?(_ elements: [Element], rows: Int) { guard elements.count % rows == 0 else { return nil } self.elements = elements self.rows = rows self.columns = elements.count / rows } - public init?(elements: [Element], columns: Int) { + public init?(_ elements: [Element], columns: Int = 1) { guard elements.count % columns == 0 else { return nil } self.elements = elements self.columns = columns From 2caca02e67295855491bc7dd80d385210682c3b5 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Fri, 23 Nov 2018 18:38:41 +0900 Subject: [PATCH 4/9] :tada: Add protocols #122 --- .../1968/Brown&Jenkins(1968).swift | 93 ++++-- OperantKit.xcodeproj/project.pbxproj | 308 ++++++++++++++++-- .../Contents.swift | 139 ++++++++ .../contents.xcplayground | 4 + Sources/Application/Enums/ExitCondition.swift | 13 + .../Protocols/DiscreteTrialParameter.swift | 13 + .../Protocols/DiscreteTrialRecordable.swift | 12 + .../Protocols/DiscreteTrialRepository.swift | 13 + .../Protocols/DiscreteTrialUseCase.swift | 12 + .../Protocols/ExperimentDataStore.swift | 12 - .../Protocols/ExperimentRecordable.swift | 15 + .../Protocols/FixedParameter.swift | 12 + .../Application/Protocols/LogUseCase.swift | 25 -- Sources/Application/Protocols/Loggable.swift | 6 +- .../Protocols/RandomParameter.swift | 12 + .../Protocols/RandomRecordable.swift | 12 + ...taStore.swift => ResponseRecordable.swift} | 18 +- .../Protocols/ScheduleParameterable.swift | 13 + .../Protocols/ScheduleRecordable.swift | 13 + .../Protocols/ScheduleRepository.swift | 17 + .../Protocols/TrialParameter.swift | 13 + .../Protocols/TrialRecordable.swift | 13 + .../Protocols/VariableParameter.swift | 12 + .../Protocols/VariableRecordable.swift | 12 + .../DiscreteTrialDataStoreImpl.swift | 20 ++ .../DataStores/ScheduleDataStoreImpl.swift | 22 ++ .../DiscreteTrialRepositoryImpl.swift | 28 ++ .../ScheduleRespositoryImpl.swift | 106 ++++++ .../UseCases/AlternativeScheduleUseCase.swift | 46 +++ .../UseCases/DiscreteTrialUseCaseImpl.swift | 16 + 30 files changed, 947 insertions(+), 103 deletions(-) create mode 100644 OperantKitPlayground.playground/Contents.swift create mode 100644 OperantKitPlayground.playground/contents.xcplayground create mode 100644 Sources/Application/Enums/ExitCondition.swift create mode 100644 Sources/Application/Protocols/DiscreteTrialParameter.swift create mode 100644 Sources/Application/Protocols/DiscreteTrialRecordable.swift create mode 100644 Sources/Application/Protocols/DiscreteTrialRepository.swift create mode 100644 Sources/Application/Protocols/DiscreteTrialUseCase.swift delete mode 100644 Sources/Application/Protocols/ExperimentDataStore.swift create mode 100644 Sources/Application/Protocols/ExperimentRecordable.swift create mode 100644 Sources/Application/Protocols/FixedParameter.swift delete mode 100644 Sources/Application/Protocols/LogUseCase.swift create mode 100644 Sources/Application/Protocols/RandomParameter.swift create mode 100644 Sources/Application/Protocols/RandomRecordable.swift rename Sources/Application/Protocols/{LogDataStore.swift => ResponseRecordable.swift} (62%) create mode 100644 Sources/Application/Protocols/ScheduleParameterable.swift create mode 100644 Sources/Application/Protocols/ScheduleRecordable.swift create mode 100644 Sources/Application/Protocols/ScheduleRepository.swift create mode 100644 Sources/Application/Protocols/TrialParameter.swift create mode 100644 Sources/Application/Protocols/TrialRecordable.swift create mode 100644 Sources/Application/Protocols/VariableParameter.swift create mode 100644 Sources/Application/Protocols/VariableRecordable.swift create mode 100644 Sources/Data/DataStores/DiscreteTrialDataStoreImpl.swift create mode 100644 Sources/Data/DataStores/ScheduleDataStoreImpl.swift create mode 100644 Sources/Data/Repositories/DiscreteTrialRepositoryImpl.swift create mode 100644 Sources/Data/Repositories/ScheduleRespositoryImpl.swift create mode 100644 Sources/Domain/UseCases/AlternativeScheduleUseCase.swift create mode 100644 Sources/Domain/UseCases/DiscreteTrialUseCaseImpl.swift diff --git a/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift b/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift index 7a01ea3..657c81b 100644 --- a/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift +++ b/Examples/CLI/journals/Sources/journals/JournalOfTheExperimentalAnalysisOfBehavior/1968/Brown&Jenkins(1968).swift @@ -9,6 +9,54 @@ import RxSwift import RxCocoa import OperantKit +public extension ObservableType { + func count() -> Observable { + return scan(0) { n, _ in n + 1 } + } + + func getTime(_ timer: TimerUseCase) -> Observable { + return flatMap { _ in timer.elapsed() } + } + + func response(_ timer: TimerUseCase) -> Observable { + return Observable.zip(count(), getTime(timer)) + .map { ResponseEntity.init(numOfResponses: $0.0, milliseconds: $0.1) } + } +} + +public extension PublishSubject where E == Milliseconds { + var shared: Observable { + return distinctUntilChanged() + .share(replay: 1) + } +} + +/// + +public enum ExitCondition { + case reinforcement(Int) + case time(Milliseconds) +} + +public protocol TrialParameter { + var schedules: [ScheduleUseCase] { get } + var exitCondition: ExitCondition { get } +} + +public protocol TrialRecordable { + var startTime: Milliseconds { get set } + var startEntities: ResponseEntity { get set } +} + +public protocol DiscreteTrialParameter { + var maxTrials: Int { get } + var trials: Matrix { get } +} + +public protocol DiscreteTrialRecordable { + var trials: Matrix { get } +} + /// Brown, P. L., & Jenkins, H. M. (1968). AUTO‐SHAPING OF THE PIGEON'S KEY‐PECK 1. Journal of the experimental analysis of behavior, 11(1), 1-8. /// - DOI: https://dx.doi.org/10.1901/jeab.1968.11-1 /// - Available link: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1338436/ @@ -17,7 +65,7 @@ class BrownAndJenkins1968 { let numberOfPairings: Int = 80 let whiteKeyLightDuration: Seconds = 8 let trayOperatingDuration: Milliseconds = 4000 - let interTrialInterval: [Seconds] = [Seconds](30...90) + let interTrialInterval: [Seconds] = [Seconds](5...10) // (30...90) .filter({ $0 % 5 == 0 }) .map { TimeUnit.seconds.milliseconds($0) } .shuffled() @@ -29,31 +77,20 @@ class BrownAndJenkins1968 { } let timer = WhileLoopTimerUseCase(priority: .high) - let schedule: ScheduleUseCase = FT(whiteKeyLightDuration) + let fixedTimeSchedule = FT(whiteKeyLightDuration) + let continuousReinforcementSchedule = CRF() let responseAction = PublishSubject() let startTimerAction = PublishSubject() let finishTimerAction = PublishSubject() var isSessionFlag = true + let duringSR = BehaviorRelay(value: false) var disposeBag = DisposeBag() - let numOfResponses = responseAction - .scan(0) { n, _ in n + 1 } - .asObservable() - - let responseTimeMilliseconds = responseAction - .asObservable() - .flatMap { _ in timer.elapsed() } - - Observable.zip(numOfResponses, responseTimeMilliseconds) - .map { ResponseEntity(numOfResponses: $0.0, milliseconds: $0.1) } + let respnseObservable = responseAction.response(timer) .do(onNext: { print("Response: \($0.numOfResponses), \($0.milliseconds)ms") }) - .subscribe() - .disposed(by: disposeBag) - let milliseconds = timer.milliseconds + let milliseconds = timer.milliseconds.shared .filter({ $0 % 1000 == 0 }) - .distinctUntilChanged() - .share(replay: 1) let firstStart = milliseconds.take(1) @@ -67,13 +104,18 @@ class BrownAndJenkins1968 { .map { ResponseEntity(numOfResponses: 0, milliseconds: $0) } .share(replay: 1) - let reinforcementOn = schedule.decision(timeObservable) + let reinforcementOn = Observable.merge( + fixedTimeSchedule.decision(timeObservable), + continuousReinforcementSchedule.decision(respnseObservable) + ) + .filter({ _ in !duringSR.value }) .filter({ $0.isReinforcement }) .share(replay: 1) let reinforcementOff = reinforcementOn .do(onNext: { print("SR on: \($0.entity.milliseconds)ms (IRI: \(trayOperatingDuration)ms)") }) - .extend(time: trayOperatingDuration, entities: schedule.extendEntity) + .storeResponse(fixedTimeSchedule.dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + .extend(time: trayOperatingDuration, entities: fixedTimeSchedule.extendEntity) .flatMap { timer.delay(trayOperatingDuration, currentTime: $0.entity.milliseconds) } .do(onNext: { print("SR off: \($0)ms") }) .asObservable() @@ -82,10 +124,10 @@ class BrownAndJenkins1968 { let nextTrial = Observable.merge( firstStart, reinforcementOff - ) + ) .do(onNext: { _ in updateInterval() }) .do(onNext: { print("ITI on: \($0)ms (Next ITI: \(nextInterval)ms)") }) - .extend(time: { nextInterval }, entities: schedule.extendEntity) + .extend(time: { nextInterval }, entities: fixedTimeSchedule.extendEntity) .flatMap { timer.delay(nextInterval, currentTime: $0) } .do(onNext: { print("ITI off: \($0)ms") }) .asObservable() @@ -102,13 +144,20 @@ class BrownAndJenkins1968 { .disposed(by: disposeBag) reinforcementOff - .scan(0) { n, _ in n + 1 } + .count() .do(onNext: { print("Trial \($0)/\(numberOfPairings) finished") }) .filter({ $0 >= numberOfPairings }) .mapToVoid() .bind(to: finishTimerAction) .disposed(by: disposeBag) + Observable.merge( + reinforcementOn.map { _ in true }, + reinforcementOff.map { _ in false } + ) + .bind(to: duringSR) + .disposed(by: disposeBag) + startTimerAction .flatMap { timer.start() } .subscribe() diff --git a/OperantKit.xcodeproj/project.pbxproj b/OperantKit.xcodeproj/project.pbxproj index cb533c1..4f2881a 100644 --- a/OperantKit.xcodeproj/project.pbxproj +++ b/OperantKit.xcodeproj/project.pbxproj @@ -14,6 +14,90 @@ 996564D321A63E3D004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; 996564D421A63E3D004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; 996564D521A63E3E004C76F0 /* PublishSubject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996564D121A63E39004C76F0 /* PublishSubject+.swift */; }; + 9965650421A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650321A64784004C76F0 /* AlternativeScheduleUseCase.swift */; }; + 9965650521A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650321A64784004C76F0 /* AlternativeScheduleUseCase.swift */; }; + 9965650621A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650321A64784004C76F0 /* AlternativeScheduleUseCase.swift */; }; + 9965650721A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650321A64784004C76F0 /* AlternativeScheduleUseCase.swift */; }; + 9965651021A658E8004C76F0 /* TrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650F21A658E8004C76F0 /* TrialRecordable.swift */; }; + 9965651121A658E8004C76F0 /* TrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650F21A658E8004C76F0 /* TrialRecordable.swift */; }; + 9965651221A658E8004C76F0 /* TrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650F21A658E8004C76F0 /* TrialRecordable.swift */; }; + 9965651321A658E8004C76F0 /* TrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965650F21A658E8004C76F0 /* TrialRecordable.swift */; }; + 9965651821A65922004C76F0 /* TrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651721A65922004C76F0 /* TrialParameter.swift */; }; + 9965651921A65922004C76F0 /* TrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651721A65922004C76F0 /* TrialParameter.swift */; }; + 9965651A21A65922004C76F0 /* TrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651721A65922004C76F0 /* TrialParameter.swift */; }; + 9965651B21A65922004C76F0 /* TrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651721A65922004C76F0 /* TrialParameter.swift */; }; + 9965651D21A65938004C76F0 /* ExitCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651C21A65938004C76F0 /* ExitCondition.swift */; }; + 9965651E21A65938004C76F0 /* ExitCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651C21A65938004C76F0 /* ExitCondition.swift */; }; + 9965651F21A65938004C76F0 /* ExitCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651C21A65938004C76F0 /* ExitCondition.swift */; }; + 9965652021A65938004C76F0 /* ExitCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965651C21A65938004C76F0 /* ExitCondition.swift */; }; + 9965652221A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652121A65966004C76F0 /* DiscreteTrialParameter.swift */; }; + 9965652321A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652121A65966004C76F0 /* DiscreteTrialParameter.swift */; }; + 9965652421A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652121A65966004C76F0 /* DiscreteTrialParameter.swift */; }; + 9965652521A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652121A65966004C76F0 /* DiscreteTrialParameter.swift */; }; + 9965652721A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */; }; + 9965652821A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */; }; + 9965652921A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */; }; + 9965652A21A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */; }; + 9965653D21A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */; }; + 9965653E21A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */; }; + 9965653F21A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */; }; + 9965654021A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */; }; + 9965654221A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */; }; + 9965654321A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */; }; + 9965654421A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */; }; + 9965654521A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */; }; + 9965654A21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */; }; + 9965654B21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */; }; + 9965654C21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */; }; + 9965654D21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */; }; + 9965654F21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */; }; + 9965655021A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */; }; + 9965655121A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */; }; + 9965655221A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */; }; + 9965655421A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */; }; + 9965655521A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */; }; + 9965655621A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */; }; + 9965655721A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */; }; + 9965655921A67731004C76F0 /* VariableParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655821A67731004C76F0 /* VariableParameter.swift */; }; + 9965655A21A67731004C76F0 /* VariableParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655821A67731004C76F0 /* VariableParameter.swift */; }; + 9965655B21A67731004C76F0 /* VariableParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655821A67731004C76F0 /* VariableParameter.swift */; }; + 9965655C21A67731004C76F0 /* VariableParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655821A67731004C76F0 /* VariableParameter.swift */; }; + 9965655E21A67765004C76F0 /* VariableRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655D21A67765004C76F0 /* VariableRecordable.swift */; }; + 9965655F21A67765004C76F0 /* VariableRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655D21A67765004C76F0 /* VariableRecordable.swift */; }; + 9965656021A67765004C76F0 /* VariableRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655D21A67765004C76F0 /* VariableRecordable.swift */; }; + 9965656121A67765004C76F0 /* VariableRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965655D21A67765004C76F0 /* VariableRecordable.swift */; }; + 9965656321A67825004C76F0 /* FixedParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656221A67825004C76F0 /* FixedParameter.swift */; }; + 9965656421A67825004C76F0 /* FixedParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656221A67825004C76F0 /* FixedParameter.swift */; }; + 9965656521A67825004C76F0 /* FixedParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656221A67825004C76F0 /* FixedParameter.swift */; }; + 9965656621A67825004C76F0 /* FixedParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656221A67825004C76F0 /* FixedParameter.swift */; }; + 9965656821A67898004C76F0 /* RandomRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656721A67898004C76F0 /* RandomRecordable.swift */; }; + 9965656921A67898004C76F0 /* RandomRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656721A67898004C76F0 /* RandomRecordable.swift */; }; + 9965656A21A67898004C76F0 /* RandomRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656721A67898004C76F0 /* RandomRecordable.swift */; }; + 9965656B21A67898004C76F0 /* RandomRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656721A67898004C76F0 /* RandomRecordable.swift */; }; + 9965656D21A678D7004C76F0 /* RandomParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656C21A678D7004C76F0 /* RandomParameter.swift */; }; + 9965656E21A678D7004C76F0 /* RandomParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656C21A678D7004C76F0 /* RandomParameter.swift */; }; + 9965656F21A678D7004C76F0 /* RandomParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656C21A678D7004C76F0 /* RandomParameter.swift */; }; + 9965657021A678D7004C76F0 /* RandomParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965656C21A678D7004C76F0 /* RandomParameter.swift */; }; + 9965657221A67D2D004C76F0 /* ScheduleRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657121A67D2D004C76F0 /* ScheduleRepository.swift */; }; + 9965657321A67D2D004C76F0 /* ScheduleRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657121A67D2D004C76F0 /* ScheduleRepository.swift */; }; + 9965657421A67D2D004C76F0 /* ScheduleRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657121A67D2D004C76F0 /* ScheduleRepository.swift */; }; + 9965657521A67D2D004C76F0 /* ScheduleRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657121A67D2D004C76F0 /* ScheduleRepository.swift */; }; + 9965657721A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657621A686C2004C76F0 /* ScheduleRespositoryImpl.swift */; }; + 9965657821A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657621A686C2004C76F0 /* ScheduleRespositoryImpl.swift */; }; + 9965657921A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657621A686C2004C76F0 /* ScheduleRespositoryImpl.swift */; }; + 9965657A21A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657621A686C2004C76F0 /* ScheduleRespositoryImpl.swift */; }; + 9965657C21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */; }; + 9965657D21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */; }; + 9965657E21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */; }; + 9965657F21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */; }; + 9965658121A693AE004C76F0 /* ScheduleParameterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */; }; + 9965658221A693AE004C76F0 /* ScheduleParameterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */; }; + 9965658321A693AE004C76F0 /* ScheduleParameterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */; }; + 9965658421A693AE004C76F0 /* ScheduleParameterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */; }; + 9965658621A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; + 9965658721A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; + 9965658821A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; + 9965658921A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; 9998170D212C355900D9F6E5 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170B212C355900D9F6E5 /* RxCocoa.framework */; }; 9998170E212C355900D9F6E5 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170C212C355900D9F6E5 /* RxSwift.framework */; }; 99981711212C356E00D9F6E5 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170F212C356E00D9F6E5 /* RxSwift.framework */; }; @@ -309,22 +393,18 @@ 99C751A121A08C3300DABE14 /* Concurrentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C7519F21A08C3300DABE14 /* Concurrentable.swift */; }; 99C751A221A08C3300DABE14 /* Concurrentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C7519F21A08C3300DABE14 /* Concurrentable.swift */; }; 99C751A321A08C3300DABE14 /* Concurrentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C7519F21A08C3300DABE14 /* Concurrentable.swift */; }; - 99C751A521A0933800DABE14 /* ExperimentDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentDataStore.swift */; }; - 99C751A621A0933800DABE14 /* ExperimentDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentDataStore.swift */; }; - 99C751A721A0933800DABE14 /* ExperimentDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentDataStore.swift */; }; - 99C751A821A0933800DABE14 /* ExperimentDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentDataStore.swift */; }; - 99C751AA21A0949000DABE14 /* LogDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* LogDataStore.swift */; }; - 99C751AB21A0949000DABE14 /* LogDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* LogDataStore.swift */; }; - 99C751AC21A0949000DABE14 /* LogDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* LogDataStore.swift */; }; - 99C751AD21A0949000DABE14 /* LogDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* LogDataStore.swift */; }; + 99C751A521A0933800DABE14 /* ExperimentRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentRecordable.swift */; }; + 99C751A621A0933800DABE14 /* ExperimentRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentRecordable.swift */; }; + 99C751A721A0933800DABE14 /* ExperimentRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentRecordable.swift */; }; + 99C751A821A0933800DABE14 /* ExperimentRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A421A0933800DABE14 /* ExperimentRecordable.swift */; }; + 99C751AA21A0949000DABE14 /* ResponseRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* ResponseRecordable.swift */; }; + 99C751AB21A0949000DABE14 /* ResponseRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* ResponseRecordable.swift */; }; + 99C751AC21A0949000DABE14 /* ResponseRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* ResponseRecordable.swift */; }; + 99C751AD21A0949000DABE14 /* ResponseRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751A921A0949000DABE14 /* ResponseRecordable.swift */; }; 99C751AF21A0949A00DABE14 /* Loggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751AE21A0949A00DABE14 /* Loggable.swift */; }; 99C751B021A0949A00DABE14 /* Loggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751AE21A0949A00DABE14 /* Loggable.swift */; }; 99C751B121A0949A00DABE14 /* Loggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751AE21A0949A00DABE14 /* Loggable.swift */; }; 99C751B221A0949A00DABE14 /* Loggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751AE21A0949A00DABE14 /* Loggable.swift */; }; - 99C751B421A094A600DABE14 /* LogUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751B321A094A600DABE14 /* LogUseCase.swift */; }; - 99C751B521A094A600DABE14 /* LogUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751B321A094A600DABE14 /* LogUseCase.swift */; }; - 99C751B621A094A600DABE14 /* LogUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751B321A094A600DABE14 /* LogUseCase.swift */; }; - 99C751B721A094A600DABE14 /* LogUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751B321A094A600DABE14 /* LogUseCase.swift */; }; 99C751BC21A098BD00DABE14 /* Discriminateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751BB21A098BD00DABE14 /* Discriminateable.swift */; }; 99C751BD21A098BD00DABE14 /* Discriminateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751BB21A098BD00DABE14 /* Discriminateable.swift */; }; 99C751BE21A098BD00DABE14 /* Discriminateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C751BB21A098BD00DABE14 /* Discriminateable.swift */; }; @@ -396,6 +476,28 @@ 994FFF5D212C2918000F4702 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = ""; }; 9965649E21A4FBCA004C76F0 /* ObservableMilliseconds+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObservableMilliseconds+.swift"; sourceTree = ""; }; 996564D121A63E39004C76F0 /* PublishSubject+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublishSubject+.swift"; sourceTree = ""; }; + 9965650321A64784004C76F0 /* AlternativeScheduleUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlternativeScheduleUseCase.swift; sourceTree = ""; }; + 9965650F21A658E8004C76F0 /* TrialRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrialRecordable.swift; sourceTree = ""; }; + 9965651721A65922004C76F0 /* TrialParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrialParameter.swift; sourceTree = ""; }; + 9965651C21A65938004C76F0 /* ExitCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExitCondition.swift; sourceTree = ""; }; + 9965652121A65966004C76F0 /* DiscreteTrialParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialParameter.swift; sourceTree = ""; }; + 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialRecordable.swift; sourceTree = ""; }; + 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialRepository.swift; sourceTree = ""; }; + 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialUseCase.swift; sourceTree = ""; }; + 9965654821A66CDA004C76F0 /* OperantKitPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = OperantKitPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialRepositoryImpl.swift; sourceTree = ""; }; + 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialUseCaseImpl.swift; sourceTree = ""; }; + 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialDataStoreImpl.swift; sourceTree = ""; }; + 9965655821A67731004C76F0 /* VariableParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariableParameter.swift; sourceTree = ""; }; + 9965655D21A67765004C76F0 /* VariableRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariableRecordable.swift; sourceTree = ""; }; + 9965656221A67825004C76F0 /* FixedParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FixedParameter.swift; sourceTree = ""; }; + 9965656721A67898004C76F0 /* RandomRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomRecordable.swift; sourceTree = ""; }; + 9965656C21A678D7004C76F0 /* RandomParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomParameter.swift; sourceTree = ""; }; + 9965657121A67D2D004C76F0 /* ScheduleRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleRepository.swift; sourceTree = ""; }; + 9965657621A686C2004C76F0 /* ScheduleRespositoryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleRespositoryImpl.swift; sourceTree = ""; }; + 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleDataStoreImpl.swift; sourceTree = ""; }; + 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleParameterable.swift; sourceTree = ""; }; + 9965658521A69410004C76F0 /* ScheduleRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleRecordable.swift; sourceTree = ""; }; 9998170B212C355900D9F6E5 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/Mac/RxCocoa.framework; sourceTree = ""; }; 9998170C212C355900D9F6E5 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/Mac/RxSwift.framework; sourceTree = ""; }; 9998170F212C356E00D9F6E5 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; @@ -485,10 +587,9 @@ 99C7519521A07A5600DABE14 /* Times.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Times.swift; sourceTree = ""; }; 99C7519A21A07E0300DABE14 /* TimeUnitable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeUnitable.swift; sourceTree = ""; }; 99C7519F21A08C3300DABE14 /* Concurrentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Concurrentable.swift; sourceTree = ""; }; - 99C751A421A0933800DABE14 /* ExperimentDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperimentDataStore.swift; sourceTree = ""; }; - 99C751A921A0949000DABE14 /* LogDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDataStore.swift; sourceTree = ""; }; + 99C751A421A0933800DABE14 /* ExperimentRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperimentRecordable.swift; sourceTree = ""; }; + 99C751A921A0949000DABE14 /* ResponseRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseRecordable.swift; sourceTree = ""; }; 99C751AE21A0949A00DABE14 /* Loggable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loggable.swift; sourceTree = ""; }; - 99C751B321A094A600DABE14 /* LogUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogUseCase.swift; sourceTree = ""; }; 99C751BB21A098BD00DABE14 /* Discriminateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Discriminateable.swift; sourceTree = ""; }; 99C751C021A09D7300DABE14 /* Chainable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Chainable.swift; sourceTree = ""; }; 99C752F221A2C64C00DABE14 /* Priority.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Priority.swift; sourceTree = ""; }; @@ -593,6 +694,59 @@ name = "Supporting Files"; sourceTree = ""; }; + 9965650221A64753004C76F0 /* CompoundSchedules */ = { + isa = PBXGroup; + children = ( + 9965650321A64784004C76F0 /* AlternativeScheduleUseCase.swift */, + ); + name = CompoundSchedules; + sourceTree = ""; + }; + 9965650921A657C1004C76F0 /* Repositories */ = { + isa = PBXGroup; + children = ( + 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */, + 9965657621A686C2004C76F0 /* ScheduleRespositoryImpl.swift */, + ); + path = Repositories; + sourceTree = ""; + }; + 9965651521A65906004C76F0 /* Parameters */ = { + isa = PBXGroup; + children = ( + 9965651721A65922004C76F0 /* TrialParameter.swift */, + 9965652121A65966004C76F0 /* DiscreteTrialParameter.swift */, + 9965656221A67825004C76F0 /* FixedParameter.swift */, + 9965656C21A678D7004C76F0 /* RandomParameter.swift */, + 9965655821A67731004C76F0 /* VariableParameter.swift */, + 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */, + ); + name = Parameters; + sourceTree = ""; + }; + 9965651621A6590D004C76F0 /* Recordables */ = { + isa = PBXGroup; + children = ( + 9965650F21A658E8004C76F0 /* TrialRecordable.swift */, + 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */, + 99C751A421A0933800DABE14 /* ExperimentRecordable.swift */, + 99C751A921A0949000DABE14 /* ResponseRecordable.swift */, + 9965655D21A67765004C76F0 /* VariableRecordable.swift */, + 9965656721A67898004C76F0 /* RandomRecordable.swift */, + 9965658521A69410004C76F0 /* ScheduleRecordable.swift */, + ); + name = Recordables; + sourceTree = ""; + }; + 9965653121A661D1004C76F0 /* Repositories */ = { + isa = PBXGroup; + children = ( + 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */, + 9965657121A67D2D004C76F0 /* ScheduleRepository.swift */, + ); + name = Repositories; + sourceTree = ""; + }; 99981705212C34D100D9F6E5 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -713,9 +867,11 @@ 999C7C7D21951CDA0044C47E /* UseCases */ = { isa = PBXGroup; children = ( + 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */, 99C74EFE219A763F00DABE14 /* Timer */, 999C7C7E21951CDA0044C47E /* ConcurrentScheduleUseCase.swift */, 99C74EFF219A764E00DABE14 /* SimpleSchedules */, + 9965650221A64753004C76F0 /* CompoundSchedules */, ); path = UseCases; sourceTree = ""; @@ -725,6 +881,7 @@ children = ( 999C7C8921951CDA0044C47E /* DataStores */, 999C7C8E21951CDA0044C47E /* Entities */, + 9965650921A657C1004C76F0 /* Repositories */, ); path = Data; sourceTree = ""; @@ -736,6 +893,8 @@ 999C7C8B21951CDA0044C47E /* FixedResponseDataStore.swift */, 999C7C8C21951CDA0044C47E /* RandomResponseDataStore.swift */, 999C7C8D21951CDA0044C47E /* ConcurrentResponseDataStore.swift */, + 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */, + 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */, ); path = DataStores; sourceTree = ""; @@ -782,6 +941,7 @@ 99C752F221A2C64C00DABE14 /* Priority.swift */, 999C7C9C21951CDB0044C47E /* TimeUnit.swift */, 99AE65C421A2DC670090B308 /* ExperimentType.swift */, + 9965651C21A65938004C76F0 /* ExitCondition.swift */, ); path = Enums; sourceTree = ""; @@ -801,7 +961,8 @@ isa = PBXGroup; children = ( 99C751BA21A0956F00DABE14 /* Units */, - 99C751B921A0954400DABE14 /* DataStore */, + 99C751B921A0954400DABE14 /* DataStores */, + 9965653121A661D1004C76F0 /* Repositories */, 99C751B821A0953B00DABE14 /* UseCases */, 999C7CA521951CDB0044C47E /* ScheduleParameter.swift */, ); @@ -924,19 +1085,19 @@ isa = PBXGroup; children = ( 99C752FC21A2C68900DABE14 /* TimerUseCase.swift */, - 99C751B321A094A600DABE14 /* LogUseCase.swift */, 999C7C7F21951CDA0044C47E /* ScheduleUseCase.swift */, + 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */, ); name = UseCases; sourceTree = ""; }; - 99C751B921A0954400DABE14 /* DataStore */ = { + 99C751B921A0954400DABE14 /* DataStores */ = { isa = PBXGroup; children = ( - 99C751A421A0933800DABE14 /* ExperimentDataStore.swift */, - 99C751A921A0949000DABE14 /* LogDataStore.swift */, + 9965651621A6590D004C76F0 /* Recordables */, + 9965651521A65906004C76F0 /* Parameters */, ); - name = DataStore; + name = DataStores; sourceTree = ""; }; 99C751BA21A0956F00DABE14 /* Units */ = { @@ -986,6 +1147,7 @@ OBJ_5 = { isa = PBXGroup; children = ( + 9965654821A66CDA004C76F0 /* OperantKitPlayground.playground */, OBJ_6 /* Package.swift */, 994FFF5B212C27B3000F4702 /* Supporting Files */, OBJ_7 /* Sources */, @@ -1329,6 +1491,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9965657321A67D2D004C76F0 /* ScheduleRepository.swift in Sources */, 999C7D2421951CDC0044C47E /* ObservableType+.swift in Sources */, 999C7D1821951CDC0044C47E /* TimeUnit.swift in Sources */, 99C7531221A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, @@ -1343,28 +1506,35 @@ 99C7518821A077AB00DABE14 /* Responsible.swift in Sources */, 999C7CDC21951CDC0044C47E /* FixedRatioScheduleUseCase.swift in Sources */, 99C752F421A2C64E00DABE14 /* Priority.swift in Sources */, + 9965655021A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */, + 9965657821A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */, 999C7CA921951CDB0044C47E /* RR.swift in Sources */, 999C7CC421951CDB0044C47E /* PostpositionSchedule.swift in Sources */, 999C7CAF21951CDB0044C47E /* FI.swift in Sources */, + 9965651121A658E8004C76F0 /* TrialRecordable.swift in Sources */, 999C7CD621951CDB0044C47E /* ScheduleUseCase.swift in Sources */, 99C752F921A2C66A00DABE14 /* UInt64+.swift in Sources */, 999C7D0621951CDC0044C47E /* RandomEntity.swift in Sources */, 99C751A121A08C3300DABE14 /* Concurrentable.swift in Sources */, 99C7518121A06ED100DABE14 /* ScheduleUseCase+.swift in Sources */, 999C7D0F21951CDC0044C47E /* DecisionSchedule.swift in Sources */, + 9965652821A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, 999C7CBE21951CDB0044C47E /* ScheduleType.swift in Sources */, 999C7D0C21951CDC0044C47E /* FixedEntity.swift in Sources */, 99C7519221A079A200DABE14 /* Discreteable.swift in Sources */, 999C7D0921951CDC0044C47E /* VariableEntity.swift in Sources */, 99C752FE21A2C68A00DABE14 /* TimerUseCase.swift in Sources */, 99AE65C121A2D6130090B308 /* Continuable.swift in Sources */, + 9965655A21A67731004C76F0 /* VariableParameter.swift in Sources */, 999C7CF421951CDC0044C47E /* FixedResponseDataStore.swift in Sources */, 999C7D3321951CDC0044C47E /* Matrix.swift in Sources */, 999C7CC121951CDB0044C47E /* PrepositionSchedule.swift in Sources */, - 99C751B521A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530321A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 9965658221A693AE004C76F0 /* ScheduleParameterable.swift in Sources */, 996564D321A63E3D004C76F0 /* PublishSubject+.swift in Sources */, 999C7D3021951CDC0044C47E /* Shared.swift in Sources */, + 9965656921A67898004C76F0 /* RandomRecordable.swift in Sources */, + 9965658721A69410004C76F0 /* ScheduleRecordable.swift in Sources */, 99C751B021A0949A00DABE14 /* Loggable.swift in Sources */, 999C7D0021951CDC0044C47E /* ResponseEntity.swift in Sources */, 99C74F0C219A77B000DABE14 /* RT.swift in Sources */, @@ -1373,23 +1543,33 @@ 999C7CEB21951CDC0044C47E /* RandomIntervalScheduleUseCase.swift in Sources */, 999C7D1E21951CDC0044C47E /* UIApplication+Rx.swift in Sources */, 999C7CDF21951CDC0044C47E /* VariableRatioScheduleUseCase.swift in Sources */, + 9965656E21A678D7004C76F0 /* RandomParameter.swift in Sources */, + 9965656421A67825004C76F0 /* FixedParameter.swift in Sources */, 99C74EF3219A702C00DABE14 /* FT.swift in Sources */, + 9965652321A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */, 99C74F02219A771700DABE14 /* VariableTimeScheduleUseCase.swift in Sources */, 999C7CD321951CDB0044C47E /* ConcurrentScheduleUseCase.swift in Sources */, 999C7CEE21951CDC0044C47E /* VariableIntervalScheduleUseCase.swift in Sources */, + 9965655F21A67765004C76F0 /* VariableRecordable.swift in Sources */, 99C7518D21A0794100DABE14 /* Reinforceable.swift in Sources */, - 99C751A621A0933800DABE14 /* ExperimentDataStore.swift in Sources */, + 9965651E21A65938004C76F0 /* ExitCondition.swift in Sources */, + 99C751A621A0933800DABE14 /* ExperimentRecordable.swift in Sources */, 99C74F07219A778A00DABE14 /* RandomTimeScheduleUseCase.swift in Sources */, 99C7519721A07A5600DABE14 /* Times.swift in Sources */, + 9965654B21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */, 999C7D2721951CDC0044C47E /* ReinforcementResult+Rx.swift in Sources */, 999C7D0321951CDC0044C47E /* ConcurrentEntity.swift in Sources */, 99C7530E21A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, - 99C751AB21A0949000DABE14 /* LogDataStore.swift in Sources */, + 99C751AB21A0949000DABE14 /* ResponseRecordable.swift in Sources */, + 9965650521A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, + 9965655521A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, 99C74EFB219A761400DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, + 9965653E21A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */, 999C7CBB21951CDB0044C47E /* VI.swift in Sources */, 999C7CD921951CDB0044C47E /* FixedIntervalScheduleUseCase.swift in Sources */, 99AE65C621A2DC670090B308 /* ExperimentType.swift in Sources */, 99C751C221A09D7300DABE14 /* Chainable.swift in Sources */, + 9965651921A65922004C76F0 /* TrialParameter.swift in Sources */, 999C7CF721951CDC0044C47E /* RandomResponseDataStore.swift in Sources */, 999C7D1B21951CDC0044C47E /* Observable+.swift in Sources */, 999C7CD021951CDB0044C47E /* FleshlerHoffman.swift in Sources */, @@ -1397,8 +1577,10 @@ 999C7CB221951CDB0044C47E /* FR.swift in Sources */, 999C7D2D21951CDC0044C47E /* ScheduleParameter.swift in Sources */, 99C74F0D219A77B300DABE14 /* VT.swift in Sources */, + 9965657D21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */, 999C7CF121951CDC0044C47E /* VariableResponseDataStore.swift in Sources */, 999C7CB821951CDB0044C47E /* VR.swift in Sources */, + 9965654321A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */, 999C7D2A21951CDC0044C47E /* UIViewController+Rx.swift in Sources */, 999C7CFA21951CDC0044C47E /* ConcurrentResponseDataStore.swift in Sources */, ); @@ -1429,6 +1611,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9965650421A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, 999C7D2521951CDC0044C47E /* ObservableType+.swift in Sources */, 99C74F01219A771700DABE14 /* VariableTimeScheduleUseCase.swift in Sources */, 99C7531121A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, @@ -1437,8 +1620,11 @@ 999C7D1921951CDC0044C47E /* TimeUnit.swift in Sources */, 999C7CFE21951CDC0044C47E /* ExperimentEntity.swift in Sources */, 999C7CAD21951CDB0044C47E /* RI.swift in Sources */, + 9965654A21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */, + 9965653D21A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */, 999C7CE321951CDC0044C47E /* ExtinctionScheduleUseCase.swift in Sources */, 999C7CE621951CDC0044C47E /* RandomRatioScheduleUseCase.swift in Sources */, + 9965655921A67731004C76F0 /* VariableParameter.swift in Sources */, 999C7CB621951CDB0044C47E /* EXT.swift in Sources */, 99C7518721A077AB00DABE14 /* Responsible.swift in Sources */, 999C7CC821951CDB0044C47E /* SessionEvents.swift in Sources */, @@ -1450,12 +1636,14 @@ 99C752F821A2C66A00DABE14 /* UInt64+.swift in Sources */, 996564D221A63E39004C76F0 /* PublishSubject+.swift in Sources */, 99C74EF6219A70F100DABE14 /* VT.swift in Sources */, + 9965655421A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, 99C751A021A08C3300DABE14 /* Concurrentable.swift in Sources */, 99C7518021A06ED100DABE14 /* ScheduleUseCase+.swift in Sources */, 999C7CD721951CDB0044C47E /* ScheduleUseCase.swift in Sources */, 999C7D0721951CDC0044C47E /* RandomEntity.swift in Sources */, 999C7D1021951CDC0044C47E /* DecisionSchedule.swift in Sources */, 999C7CBF21951CDB0044C47E /* ScheduleType.swift in Sources */, + 9965658121A693AE004C76F0 /* ScheduleParameterable.swift in Sources */, 99C7519121A079A200DABE14 /* Discreteable.swift in Sources */, 99C752FD21A2C68A00DABE14 /* TimerUseCase.swift in Sources */, 99AE65C021A2D6130090B308 /* Continuable.swift in Sources */, @@ -1463,40 +1651,54 @@ 9965649F21A4FBCA004C76F0 /* ObservableMilliseconds+.swift in Sources */, 999C7D0A21951CDC0044C47E /* VariableEntity.swift in Sources */, 999C7CF521951CDC0044C47E /* FixedResponseDataStore.swift in Sources */, - 99C751B421A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530221A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 9965656821A67898004C76F0 /* RandomRecordable.swift in Sources */, 999C7D3421951CDC0044C47E /* Matrix.swift in Sources */, + 9965651021A658E8004C76F0 /* TrialRecordable.swift in Sources */, 99C751AF21A0949A00DABE14 /* Loggable.swift in Sources */, + 9965654F21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */, 999C7CC221951CDB0044C47E /* PrepositionSchedule.swift in Sources */, 999C7D3121951CDC0044C47E /* Shared.swift in Sources */, + 9965651821A65922004C76F0 /* TrialParameter.swift in Sources */, 999C7D0121951CDC0044C47E /* ResponseEntity.swift in Sources */, + 9965655E21A67765004C76F0 /* VariableRecordable.swift in Sources */, 99C751BC21A098BD00DABE14 /* Discriminateable.swift in Sources */, 99C74EFA219A761000DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, 999C7D1321951CDC0044C47E /* ReinforcementResult.swift in Sources */, 999C7CEC21951CDC0044C47E /* RandomIntervalScheduleUseCase.swift in Sources */, 999C7D1F21951CDC0044C47E /* UIApplication+Rx.swift in Sources */, + 9965654221A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */, 999C7CE021951CDC0044C47E /* VariableRatioScheduleUseCase.swift in Sources */, 99C74EF1219A702400DABE14 /* FT.swift in Sources */, 999C7CD421951CDB0044C47E /* ConcurrentScheduleUseCase.swift in Sources */, + 9965657221A67D2D004C76F0 /* ScheduleRepository.swift in Sources */, 99C7518C21A0794100DABE14 /* Reinforceable.swift in Sources */, - 99C751A521A0933800DABE14 /* ExperimentDataStore.swift in Sources */, + 99C751A521A0933800DABE14 /* ExperimentRecordable.swift in Sources */, 999C7CEF21951CDC0044C47E /* VariableIntervalScheduleUseCase.swift in Sources */, 99C7519621A07A5600DABE14 /* Times.swift in Sources */, 999C7D2821951CDC0044C47E /* ReinforcementResult+Rx.swift in Sources */, + 9965657C21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */, + 9965652721A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, 999C7D0421951CDC0044C47E /* ConcurrentEntity.swift in Sources */, 99C7530D21A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, - 99C751AA21A0949000DABE14 /* LogDataStore.swift in Sources */, + 99C751AA21A0949000DABE14 /* ResponseRecordable.swift in Sources */, 99C74F06219A778A00DABE14 /* RandomTimeScheduleUseCase.swift in Sources */, 999C7CBC21951CDB0044C47E /* VI.swift in Sources */, 999C7CDA21951CDB0044C47E /* FixedIntervalScheduleUseCase.swift in Sources */, 99AE65C521A2DC670090B308 /* ExperimentType.swift in Sources */, + 9965658621A69410004C76F0 /* ScheduleRecordable.swift in Sources */, + 9965651D21A65938004C76F0 /* ExitCondition.swift in Sources */, 99C751C121A09D7300DABE14 /* Chainable.swift in Sources */, 999C7CF821951CDC0044C47E /* RandomResponseDataStore.swift in Sources */, + 9965656321A67825004C76F0 /* FixedParameter.swift in Sources */, 999C7D1C21951CDC0044C47E /* Observable+.swift in Sources */, 999C7CD121951CDB0044C47E /* FleshlerHoffman.swift in Sources */, 999C7D2221951CDC0044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7CB321951CDB0044C47E /* FR.swift in Sources */, + 9965652221A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */, + 9965657721A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */, 99C74EF8219A713D00DABE14 /* RT.swift in Sources */, + 9965656D21A678D7004C76F0 /* RandomParameter.swift in Sources */, 999C7D2E21951CDC0044C47E /* ScheduleParameter.swift in Sources */, 999C7CF221951CDC0044C47E /* VariableResponseDataStore.swift in Sources */, 999C7CB921951CDB0044C47E /* VR.swift in Sources */, @@ -1530,6 +1732,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9965657421A67D2D004C76F0 /* ScheduleRepository.swift in Sources */, 999C7D93219533150044C47E /* DecisionSchedule.swift in Sources */, 999C7D94219533150044C47E /* ReinforcementResult.swift in Sources */, 99C7531321A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, @@ -1544,28 +1747,35 @@ 999C7D9B219533150044C47E /* ReinforcementResult+Rx.swift in Sources */, 999C7D9C219533150044C47E /* UIViewController+Rx.swift in Sources */, 99C752F521A2C64E00DABE14 /* Priority.swift in Sources */, + 9965655121A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */, + 9965657921A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */, 999C7D9D219533150044C47E /* ScheduleParameter.swift in Sources */, 999C7D9E219533150044C47E /* Shared.swift in Sources */, 999C7D9F219533150044C47E /* Matrix.swift in Sources */, + 9965651221A658E8004C76F0 /* TrialRecordable.swift in Sources */, 999C7DA0219533150044C47E /* RR.swift in Sources */, 99C752FA21A2C66A00DABE14 /* UInt64+.swift in Sources */, 99C751A221A08C3300DABE14 /* Concurrentable.swift in Sources */, 99C7518221A06ED100DABE14 /* ScheduleUseCase+.swift in Sources */, 999C7DA1219533150044C47E /* RI.swift in Sources */, 999C7DA2219533150044C47E /* FI.swift in Sources */, + 9965652921A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, 999C7DA3219533150044C47E /* FR.swift in Sources */, 999C7DA4219533150044C47E /* EXT.swift in Sources */, 99C7519321A079A200DABE14 /* Discreteable.swift in Sources */, 999C7DA5219533150044C47E /* VR.swift in Sources */, 99C752FF21A2C68A00DABE14 /* TimerUseCase.swift in Sources */, 99AE65C221A2D6130090B308 /* Continuable.swift in Sources */, + 9965655B21A67731004C76F0 /* VariableParameter.swift in Sources */, 999C7DA6219533150044C47E /* VI.swift in Sources */, 999C7DA7219533150044C47E /* ScheduleType.swift in Sources */, 999C7DA8219533150044C47E /* PrepositionSchedule.swift in Sources */, - 99C751B621A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530421A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 9965658321A693AE004C76F0 /* ScheduleParameterable.swift in Sources */, 996564D421A63E3D004C76F0 /* PublishSubject+.swift in Sources */, 999C7DA9219533150044C47E /* PostpositionSchedule.swift in Sources */, + 9965656A21A67898004C76F0 /* RandomRecordable.swift in Sources */, + 9965658821A69410004C76F0 /* ScheduleRecordable.swift in Sources */, 99C751B121A0949A00DABE14 /* Loggable.swift in Sources */, 999C7DAA219533150044C47E /* SessionEvents.swift in Sources */, 99C74F0B219A77AF00DABE14 /* RT.swift in Sources */, @@ -1574,23 +1784,33 @@ 999C7DAE219533150044C47E /* VariableResponseDataStore.swift in Sources */, 999C7DAF219533150044C47E /* FixedResponseDataStore.swift in Sources */, 99C74EF2219A702B00DABE14 /* FT.swift in Sources */, + 9965656F21A678D7004C76F0 /* RandomParameter.swift in Sources */, + 9965656521A67825004C76F0 /* FixedParameter.swift in Sources */, 999C7DB0219533150044C47E /* RandomResponseDataStore.swift in Sources */, + 9965652421A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */, 99C74F03219A771700DABE14 /* VariableTimeScheduleUseCase.swift in Sources */, 999C7DB1219533150044C47E /* ConcurrentResponseDataStore.swift in Sources */, 999C7DB2219533150044C47E /* ExperimentEntity.swift in Sources */, + 9965656021A67765004C76F0 /* VariableRecordable.swift in Sources */, 99C74F08219A778A00DABE14 /* RandomTimeScheduleUseCase.swift in Sources */, + 9965651F21A65938004C76F0 /* ExitCondition.swift in Sources */, 99C7518E21A0794100DABE14 /* Reinforceable.swift in Sources */, - 99C751A721A0933800DABE14 /* ExperimentDataStore.swift in Sources */, + 99C751A721A0933800DABE14 /* ExperimentRecordable.swift in Sources */, 999C7DB3219533150044C47E /* ResponseEntity.swift in Sources */, + 9965654C21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */, 99C7519821A07A5600DABE14 /* Times.swift in Sources */, 999C7DB4219533150044C47E /* ConcurrentEntity.swift in Sources */, 99C7530F21A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, 99C74EFC219A761500DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, - 99C751AC21A0949000DABE14 /* LogDataStore.swift in Sources */, + 9965650621A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, + 9965655621A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, + 99C751AC21A0949000DABE14 /* ResponseRecordable.swift in Sources */, + 9965653F21A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */, 999C7DB5219533150044C47E /* RandomEntity.swift in Sources */, 999C7DB6219533160044C47E /* VariableEntity.swift in Sources */, 99AE65C721A2DC670090B308 /* ExperimentType.swift in Sources */, 999C7DB7219533160044C47E /* FixedEntity.swift in Sources */, + 9965651A21A65922004C76F0 /* TrialParameter.swift in Sources */, 99C751C321A09D7300DABE14 /* Chainable.swift in Sources */, 999C7DB8219533160044C47E /* ConcurrentScheduleUseCase.swift in Sources */, 999C7DB9219533160044C47E /* ScheduleUseCase.swift in Sources */, @@ -1598,8 +1818,10 @@ 999C7DBB219533160044C47E /* FixedRatioScheduleUseCase.swift in Sources */, 999C7DBC219533160044C47E /* VariableRatioScheduleUseCase.swift in Sources */, 99C74F0E219A77B400DABE14 /* VT.swift in Sources */, + 9965657E21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */, 999C7DBD219533160044C47E /* ExtinctionScheduleUseCase.swift in Sources */, 999C7DBE219533160044C47E /* RandomRatioScheduleUseCase.swift in Sources */, + 9965654421A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */, 999C7DC0219533160044C47E /* RandomIntervalScheduleUseCase.swift in Sources */, 999C7DC1219533160044C47E /* VariableIntervalScheduleUseCase.swift in Sources */, ); @@ -1630,6 +1852,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9965657521A67D2D004C76F0 /* ScheduleRepository.swift in Sources */, 999C7DE7219542610044C47E /* DecisionSchedule.swift in Sources */, 999C7DE8219542610044C47E /* ReinforcementResult.swift in Sources */, 99C7531421A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, @@ -1644,28 +1867,35 @@ 999C7DEF219542610044C47E /* ReinforcementResult+Rx.swift in Sources */, 999C7DF0219542610044C47E /* UIViewController+Rx.swift in Sources */, 99C752F621A2C64E00DABE14 /* Priority.swift in Sources */, + 9965655221A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */, + 9965657A21A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */, 999C7DF1219542610044C47E /* ScheduleParameter.swift in Sources */, 999C7DF2219542610044C47E /* Shared.swift in Sources */, 999C7DF3219542610044C47E /* Matrix.swift in Sources */, + 9965651321A658E8004C76F0 /* TrialRecordable.swift in Sources */, 999C7DF4219542610044C47E /* RR.swift in Sources */, 99C752FB21A2C66A00DABE14 /* UInt64+.swift in Sources */, 99C751A321A08C3300DABE14 /* Concurrentable.swift in Sources */, 99C7518321A06ED100DABE14 /* ScheduleUseCase+.swift in Sources */, 999C7DF5219542610044C47E /* RI.swift in Sources */, 999C7DF6219542610044C47E /* FI.swift in Sources */, + 9965652A21A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, 999C7DF7219542610044C47E /* FR.swift in Sources */, 999C7DF8219542610044C47E /* EXT.swift in Sources */, 99C7519421A079A200DABE14 /* Discreteable.swift in Sources */, 999C7DF9219542610044C47E /* VR.swift in Sources */, 99C7530021A2C68A00DABE14 /* TimerUseCase.swift in Sources */, 99AE65C321A2D6130090B308 /* Continuable.swift in Sources */, + 9965655C21A67731004C76F0 /* VariableParameter.swift in Sources */, 999C7DFA219542610044C47E /* VI.swift in Sources */, 999C7DFB219542610044C47E /* ScheduleType.swift in Sources */, 999C7DFC219542610044C47E /* PrepositionSchedule.swift in Sources */, - 99C751B721A094A600DABE14 /* LogUseCase.swift in Sources */, 99C7530521A2C69C00DABE14 /* TimeHelper.swift in Sources */, + 9965658421A693AE004C76F0 /* ScheduleParameterable.swift in Sources */, 996564D521A63E3E004C76F0 /* PublishSubject+.swift in Sources */, 999C7DFD219542610044C47E /* PostpositionSchedule.swift in Sources */, + 9965656B21A67898004C76F0 /* RandomRecordable.swift in Sources */, + 9965658921A69410004C76F0 /* ScheduleRecordable.swift in Sources */, 99C751B221A0949A00DABE14 /* Loggable.swift in Sources */, 999C7DFE219542610044C47E /* SessionEvents.swift in Sources */, 99C74F0A219A77AE00DABE14 /* RT.swift in Sources */, @@ -1674,23 +1904,33 @@ 999C7E02219542610044C47E /* VariableResponseDataStore.swift in Sources */, 999C7E03219542610044C47E /* FixedResponseDataStore.swift in Sources */, 99C74EF4219A702D00DABE14 /* FT.swift in Sources */, + 9965657021A678D7004C76F0 /* RandomParameter.swift in Sources */, + 9965656621A67825004C76F0 /* FixedParameter.swift in Sources */, 999C7E04219542610044C47E /* RandomResponseDataStore.swift in Sources */, + 9965652521A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */, 99C74F04219A771700DABE14 /* VariableTimeScheduleUseCase.swift in Sources */, 999C7E05219542610044C47E /* ConcurrentResponseDataStore.swift in Sources */, 999C7E06219542610044C47E /* ExperimentEntity.swift in Sources */, + 9965656121A67765004C76F0 /* VariableRecordable.swift in Sources */, 99C74F09219A778A00DABE14 /* RandomTimeScheduleUseCase.swift in Sources */, + 9965652021A65938004C76F0 /* ExitCondition.swift in Sources */, 99C7518F21A0794100DABE14 /* Reinforceable.swift in Sources */, - 99C751A821A0933800DABE14 /* ExperimentDataStore.swift in Sources */, + 99C751A821A0933800DABE14 /* ExperimentRecordable.swift in Sources */, 999C7E07219542610044C47E /* ResponseEntity.swift in Sources */, + 9965654D21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */, 99C7519921A07A5600DABE14 /* Times.swift in Sources */, 999C7E08219542610044C47E /* ConcurrentEntity.swift in Sources */, 99C7531021A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, 99C74EFD219A761600DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, - 99C751AD21A0949000DABE14 /* LogDataStore.swift in Sources */, + 9965650721A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, + 9965655721A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, + 99C751AD21A0949000DABE14 /* ResponseRecordable.swift in Sources */, + 9965654021A66A72004C76F0 /* DiscreteTrialRepository.swift in Sources */, 999C7E09219542610044C47E /* RandomEntity.swift in Sources */, 999C7E0A219542610044C47E /* VariableEntity.swift in Sources */, 99AE65C821A2DC670090B308 /* ExperimentType.swift in Sources */, 999C7E0B219542610044C47E /* FixedEntity.swift in Sources */, + 9965651B21A65922004C76F0 /* TrialParameter.swift in Sources */, 99C751C421A09D7300DABE14 /* Chainable.swift in Sources */, 999C7E0C219542610044C47E /* ConcurrentScheduleUseCase.swift in Sources */, 999C7E0D219542610044C47E /* ScheduleUseCase.swift in Sources */, @@ -1698,8 +1938,10 @@ 999C7E0F219542620044C47E /* FixedRatioScheduleUseCase.swift in Sources */, 999C7E10219542620044C47E /* VariableRatioScheduleUseCase.swift in Sources */, 99C74F0F219A77B500DABE14 /* VT.swift in Sources */, + 9965657F21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */, 999C7E11219542620044C47E /* ExtinctionScheduleUseCase.swift in Sources */, 999C7E12219542620044C47E /* RandomRatioScheduleUseCase.swift in Sources */, + 9965654521A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */, 999C7E14219542620044C47E /* RandomIntervalScheduleUseCase.swift in Sources */, 999C7E15219542620044C47E /* VariableIntervalScheduleUseCase.swift in Sources */, ); diff --git a/OperantKitPlayground.playground/Contents.swift b/OperantKitPlayground.playground/Contents.swift new file mode 100644 index 0000000..825192d --- /dev/null +++ b/OperantKitPlayground.playground/Contents.swift @@ -0,0 +1,139 @@ +import OperantKit +import RxCocoa +import RxSwift + +func builder() { + let useCase: DiscreteTrialUseCase = DiscreteTrialUseCaseImpl( + repository: DiscreteTrialRepositoryImpl( + dataStore: DiscreteTrialDataStoreImpl( + maxTrials: 2, + parameters: [], + records: [] + ) + ) + ) +} + +let numberOfPairings: Int = 80 +let whiteKeyLightDuration: Seconds = 8 +let trayOperatingDuration: Milliseconds = 4000 +let interTrialInterval: [Seconds] = [Seconds](5...10) // (30...90) + .filter({ $0 % 5 == 0 }) + .map { TimeUnit.seconds.milliseconds($0) } + .shuffled() + +var nextInterval: Milliseconds = 0 +var currentOrder: Int = 0 +func updateInterval() { + nextInterval = interTrialInterval[currentOrder % interTrialInterval.count] +} + +let timer = WhileLoopTimerUseCase(priority: .high) +let fixedTimeSchedule = FT(whiteKeyLightDuration) +let continuousReinforcementSchedule = CRF() +let responseAction = PublishSubject() +let startTimerAction = PublishSubject() +let finishTimerAction = PublishSubject() +var isSessionFlag = true +let duringSR = BehaviorRelay(value: false) +var disposeBag = DisposeBag() + +let respnseObservable = responseAction.response(timer) + .do(onNext: { print("Response: \($0.numOfResponses), \($0.milliseconds)ms") }) + +let milliseconds = timer.milliseconds.shared + .filter({ $0 % 1000 == 0 }) + +let firstStart = milliseconds.take(1) + +firstStart + .do(onNext: { _ in print("Session started") }) + .subscribe() + .disposed(by: disposeBag) + +let timeObservable = milliseconds + .do(onNext: { print("Time elapsed: \($0)ms") }) + .map { ResponseEntity(numOfResponses: 0, milliseconds: $0) } + .share(replay: 1) + +let reinforcementOn = Observable.merge( + fixedTimeSchedule.decision(timeObservable), + continuousReinforcementSchedule.decision(respnseObservable) + ) + .filter({ _ in !duringSR.value }) + .filter({ $0.isReinforcement }) + .share(replay: 1) + +let reinforcementOff = reinforcementOn + .do(onNext: { print("SR on: \($0.entity.milliseconds)ms (IRI: \(trayOperatingDuration)ms)") }) + .storeResponse(fixedTimeSchedule.dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + .extend(time: trayOperatingDuration, entities: fixedTimeSchedule.extendEntity) + .flatMap { timer.delay(trayOperatingDuration, currentTime: $0.entity.milliseconds) } + .do(onNext: { print("SR off: \($0)ms") }) + .asObservable() + .share(replay: 1) + +let nextTrial = Observable.merge( + firstStart, + reinforcementOff + ) + .do(onNext: { _ in updateInterval() }) + .do(onNext: { print("ITI on: \($0)ms (Next ITI: \(nextInterval)ms)") }) + .extend(time: { nextInterval }, entities: fixedTimeSchedule.extendEntity) + .flatMap { timer.delay(nextInterval, currentTime: $0) } + .do(onNext: { print("ITI off: \($0)ms") }) + .asObservable() + .share(replay: 1) + +nextTrial + .do(onNext: { _ in print("SD on") }) + .subscribe() + .disposed(by: disposeBag) + +reinforcementOn + .do(onNext: { _ in print("SD off") }) + .subscribe() + .disposed(by: disposeBag) + +reinforcementOff + .count() + .do(onNext: { print("Trial \($0)/\(numberOfPairings) finished") }) + .filter({ $0 >= numberOfPairings }) + .mapToVoid() + .bind(to: finishTimerAction) + .disposed(by: disposeBag) + +Observable.merge( + reinforcementOn.map { _ in true }, + reinforcementOff.map { _ in false } + ) + .bind(to: duringSR) + .disposed(by: disposeBag) + +startTimerAction + .flatMap { timer.start() } + .subscribe() + .disposed(by: disposeBag) + +finishTimerAction + .flatMap { timer.finish() } + .do(onNext: { print("Session finished: \($0)ms") }) + .do(onNext: { _ in print("Program ended if enter any keys") }) + .mapToVoid() + .subscribe(onNext: { + isSessionFlag = false + disposeBag = DisposeBag() + }) + .disposed(by: disposeBag) + +startTimerAction.onNext(()) +while isSessionFlag { + let input = readLine() + guard isSessionFlag else { continue } + switch input { + case "q": + finishTimerAction.onNext(()) + default: + responseAction.onNext(()) + } +} diff --git a/OperantKitPlayground.playground/contents.xcplayground b/OperantKitPlayground.playground/contents.xcplayground new file mode 100644 index 0000000..a93d484 --- /dev/null +++ b/OperantKitPlayground.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Sources/Application/Enums/ExitCondition.swift b/Sources/Application/Enums/ExitCondition.swift new file mode 100644 index 0000000..4530fd0 --- /dev/null +++ b/Sources/Application/Enums/ExitCondition.swift @@ -0,0 +1,13 @@ +// +// ExitCondition.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public enum ExitCondition { + case reinforcement(Int) + case time(Milliseconds) +} diff --git a/Sources/Application/Protocols/DiscreteTrialParameter.swift b/Sources/Application/Protocols/DiscreteTrialParameter.swift new file mode 100644 index 0000000..87d04d8 --- /dev/null +++ b/Sources/Application/Protocols/DiscreteTrialParameter.swift @@ -0,0 +1,13 @@ +// +// DiscreteTrialParameter.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol DiscreteTrialParameter { + var maxTrials: Int { get } + var parameters: [TrialParameter] { get } +} diff --git a/Sources/Application/Protocols/DiscreteTrialRecordable.swift b/Sources/Application/Protocols/DiscreteTrialRecordable.swift new file mode 100644 index 0000000..36fe573 --- /dev/null +++ b/Sources/Application/Protocols/DiscreteTrialRecordable.swift @@ -0,0 +1,12 @@ +// +// DiscreteTrialRecordable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol DiscreteTrialRecordable { + var records: [TrialRecordable] { get set } +} diff --git a/Sources/Application/Protocols/DiscreteTrialRepository.swift b/Sources/Application/Protocols/DiscreteTrialRepository.swift new file mode 100644 index 0000000..09d272b --- /dev/null +++ b/Sources/Application/Protocols/DiscreteTrialRepository.swift @@ -0,0 +1,13 @@ +// +// DiscreteTrialRepository.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol DiscreteTrialRepository { + var parameter: DiscreteTrialParameter { get } + var recorder: DiscreteTrialRecordable { get set } +} diff --git a/Sources/Application/Protocols/DiscreteTrialUseCase.swift b/Sources/Application/Protocols/DiscreteTrialUseCase.swift new file mode 100644 index 0000000..92be740 --- /dev/null +++ b/Sources/Application/Protocols/DiscreteTrialUseCase.swift @@ -0,0 +1,12 @@ +// +// DiscreteTrialUseCase.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol DiscreteTrialUseCase { + var repository: DiscreteTrialRepository { get } +} diff --git a/Sources/Application/Protocols/ExperimentDataStore.swift b/Sources/Application/Protocols/ExperimentDataStore.swift deleted file mode 100644 index 2ca316b..0000000 --- a/Sources/Application/Protocols/ExperimentDataStore.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// ExperimentDataStore.swift -// OperantKit -// -// Created by Yuto Mizutani on 2018/11/18. -// - -import Foundation - -public protocol ExperimentDataStore { - var experimentType: ExperimentType { get } -} diff --git a/Sources/Application/Protocols/ExperimentRecordable.swift b/Sources/Application/Protocols/ExperimentRecordable.swift new file mode 100644 index 0000000..e8ad36d --- /dev/null +++ b/Sources/Application/Protocols/ExperimentRecordable.swift @@ -0,0 +1,15 @@ +// +// ExperimentRecordable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/18. +// + +import Foundation + +public protocol ExperimentRecordable: class { + /// Stored ResponseEntity when previous reinforcement + var lastReinforcementEntity: ResponseEntity { get set } + /// Extend entity + var extendEntity: ResponseEntity { get set } +} diff --git a/Sources/Application/Protocols/FixedParameter.swift b/Sources/Application/Protocols/FixedParameter.swift new file mode 100644 index 0000000..5b41df1 --- /dev/null +++ b/Sources/Application/Protocols/FixedParameter.swift @@ -0,0 +1,12 @@ +// +// FixedParameter.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol FixedParameter { + var value: Int { get } +} diff --git a/Sources/Application/Protocols/LogUseCase.swift b/Sources/Application/Protocols/LogUseCase.swift deleted file mode 100644 index 9347325..0000000 --- a/Sources/Application/Protocols/LogUseCase.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// LogUseCase.swift -// OperantKit -// -// Created by Yuto Mizutani on 2018/11/18. -// - -import Foundation - -public protocol LogUseCase { - /// Stored data store - var dataStore: LogDataStore { get set } -} - -public extension LogUseCase { - /// Store elements - mutating func store(_ newElements: Responsible...) { - store(newElements) - } - - /// Store elements - mutating func store(_ newElements: [Responsible]) { - dataStore.append(newElements) - } -} diff --git a/Sources/Application/Protocols/Loggable.swift b/Sources/Application/Protocols/Loggable.swift index 330e0df..dc95771 100644 --- a/Sources/Application/Protocols/Loggable.swift +++ b/Sources/Application/Protocols/Loggable.swift @@ -9,6 +9,8 @@ import Foundation /// Log parameter requrements protocol public protocol Loggable { - /// Stored responses - var responses: [Responsible] { get set } + associatedtype Element + typealias Log = (time: Milliseconds, element: Element) + /// Stored logs + var log: [Log] { get set } } diff --git a/Sources/Application/Protocols/RandomParameter.swift b/Sources/Application/Protocols/RandomParameter.swift new file mode 100644 index 0000000..07620a4 --- /dev/null +++ b/Sources/Application/Protocols/RandomParameter.swift @@ -0,0 +1,12 @@ +// +// RandomParameter.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol RandomParameter { + var value: Int { get } +} diff --git a/Sources/Application/Protocols/RandomRecordable.swift b/Sources/Application/Protocols/RandomRecordable.swift new file mode 100644 index 0000000..f0ae284 --- /dev/null +++ b/Sources/Application/Protocols/RandomRecordable.swift @@ -0,0 +1,12 @@ +// +// RandomRecordable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol RandomRecordable { + var currentValue: Int { get set } +} diff --git a/Sources/Application/Protocols/LogDataStore.swift b/Sources/Application/Protocols/ResponseRecordable.swift similarity index 62% rename from Sources/Application/Protocols/LogDataStore.swift rename to Sources/Application/Protocols/ResponseRecordable.swift index 666eda5..304b202 100644 --- a/Sources/Application/Protocols/LogDataStore.swift +++ b/Sources/Application/Protocols/ResponseRecordable.swift @@ -1,5 +1,5 @@ // -// LogDataStore.swift +// ResponseRecordable.swift // OperantKit // // Created by Yuto Mizutani on 2018/11/18. @@ -7,12 +7,12 @@ import Foundation -public protocol LogDataStore { - /// Stored log entity - var log: Loggable { get set } +public protocol ResponseRecordable { + /// Stored responses + var responses: [Responsible] { get set } } -public extension LogDataStore { +public extension ResponseRecordable { /// Append log elements mutating func append(_ newElements: Responsible...) { append(newElements) @@ -20,7 +20,7 @@ public extension LogDataStore { /// Append log elements mutating func append(_ newElements: [Responsible]) { - log.responses += newElements + responses += newElements } /// Insert log elements at the index @@ -32,9 +32,9 @@ public extension LogDataStore { mutating func insert(_ newElements: [Responsible], at index: Int) { switch index { case ...0: - log.responses = newElements + log.responses - case let i where i < log.responses.count: - log.responses = log.responses.prefix(i) + newElements + log.responses.suffix(log.responses.count - i) + responses = newElements + responses + case let i where i < responses.count: + responses = responses.prefix(i) + newElements + responses.suffix(responses.count - i) default: append(newElements) } diff --git a/Sources/Application/Protocols/ScheduleParameterable.swift b/Sources/Application/Protocols/ScheduleParameterable.swift new file mode 100644 index 0000000..adf7893 --- /dev/null +++ b/Sources/Application/Protocols/ScheduleParameterable.swift @@ -0,0 +1,13 @@ +// +// ScheduleParameterable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol ScheduleParameterable: class { + var value: Int { get } + var values: [Int] { get set } +} diff --git a/Sources/Application/Protocols/ScheduleRecordable.swift b/Sources/Application/Protocols/ScheduleRecordable.swift new file mode 100644 index 0000000..312e8e9 --- /dev/null +++ b/Sources/Application/Protocols/ScheduleRecordable.swift @@ -0,0 +1,13 @@ +// +// ScheduleRecordable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol ScheduleRecordable: class { + var currentOrder: Int { get set } + var currentValue: Int { get set } +} diff --git a/Sources/Application/Protocols/ScheduleRepository.swift b/Sources/Application/Protocols/ScheduleRepository.swift new file mode 100644 index 0000000..ca25e10 --- /dev/null +++ b/Sources/Application/Protocols/ScheduleRepository.swift @@ -0,0 +1,17 @@ +// +// ScheduleRepository.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import RxSwift + +public protocol ScheduleRespository { + func getValue() -> Single + func nextValue(_: @escaping (ScheduleParameterable, ScheduleRecordable) -> ScheduleRecordable) -> Completable + func getExtendProperty() -> Single + func getLastReinforcementProperty() -> Single + func clearExtendProperty() -> Completable + func updateLastReinforcementProperty(_:ResponseEntity) -> Completable +} diff --git a/Sources/Application/Protocols/TrialParameter.swift b/Sources/Application/Protocols/TrialParameter.swift new file mode 100644 index 0000000..f3e13aa --- /dev/null +++ b/Sources/Application/Protocols/TrialParameter.swift @@ -0,0 +1,13 @@ +// +// TrialParameter.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol TrialParameter { + var schedule: ScheduleUseCase { get } + var exitCondition: ExitCondition { get } +} diff --git a/Sources/Application/Protocols/TrialRecordable.swift b/Sources/Application/Protocols/TrialRecordable.swift new file mode 100644 index 0000000..bb82ea7 --- /dev/null +++ b/Sources/Application/Protocols/TrialRecordable.swift @@ -0,0 +1,13 @@ +// +// TrialRecordable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol TrialRecordable { + var startTime: Milliseconds { get set } + var startEntities: ResponseEntity { get set } +} diff --git a/Sources/Application/Protocols/VariableParameter.swift b/Sources/Application/Protocols/VariableParameter.swift new file mode 100644 index 0000000..4441db8 --- /dev/null +++ b/Sources/Application/Protocols/VariableParameter.swift @@ -0,0 +1,12 @@ +// +// VariableParameter.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol VariableParameter { + var values: [Int] { get } +} diff --git a/Sources/Application/Protocols/VariableRecordable.swift b/Sources/Application/Protocols/VariableRecordable.swift new file mode 100644 index 0000000..35aaa34 --- /dev/null +++ b/Sources/Application/Protocols/VariableRecordable.swift @@ -0,0 +1,12 @@ +// +// VariableRecordable.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public protocol VariableRecordable { + var currentOrder: Int { get set } +} diff --git a/Sources/Data/DataStores/DiscreteTrialDataStoreImpl.swift b/Sources/Data/DataStores/DiscreteTrialDataStoreImpl.swift new file mode 100644 index 0000000..5903f6b --- /dev/null +++ b/Sources/Data/DataStores/DiscreteTrialDataStoreImpl.swift @@ -0,0 +1,20 @@ +// +// DiscreteTrialDataStoreImpl.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public class DiscreteTrialDataStoreImpl: DiscreteTrialParameter, DiscreteTrialRecordable { + public var maxTrials: Int + public var parameters: [TrialParameter] + public var records: [TrialRecordable] + + public init(maxTrials: Int, parameters: [TrialParameter], records: [TrialRecordable]) { + self.maxTrials = maxTrials + self.parameters = parameters + self.records = records + } +} diff --git a/Sources/Data/DataStores/ScheduleDataStoreImpl.swift b/Sources/Data/DataStores/ScheduleDataStoreImpl.swift new file mode 100644 index 0000000..a225e47 --- /dev/null +++ b/Sources/Data/DataStores/ScheduleDataStoreImpl.swift @@ -0,0 +1,22 @@ +// +// ScheduleDataStoreImpl.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public class ScheduleDataStoreImpl: ScheduleParameterable, ScheduleRecordable, ExperimentRecordable { + public var value: Int + public var values: [Int] + public var currentOrder: Int = 0 + public var currentValue: Int = 0 + public var lastReinforcementEntity: ResponseEntity = ResponseEntity() + public var extendEntity: ResponseEntity = ResponseEntity() + + public init(value: Int, values: [Int] = []) { + self.value = value + self.values = values + } +} diff --git a/Sources/Data/Repositories/DiscreteTrialRepositoryImpl.swift b/Sources/Data/Repositories/DiscreteTrialRepositoryImpl.swift new file mode 100644 index 0000000..bd5484d --- /dev/null +++ b/Sources/Data/Repositories/DiscreteTrialRepositoryImpl.swift @@ -0,0 +1,28 @@ +// +// DiscreteTrialRepositoryImpl.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public struct DiscreteTrialRepositoryImpl: DiscreteTrialRepository { + public var dataStore: DiscreteTrialDataStoreImpl + + public var parameter: DiscreteTrialParameter { + return dataStore + } + public var recorder: DiscreteTrialRecordable { + set { + dataStore.records = newValue.records + } + get { + return dataStore + } + } + + public init(dataStore: DiscreteTrialDataStoreImpl) { + self.dataStore = dataStore + } +} diff --git a/Sources/Data/Repositories/ScheduleRespositoryImpl.swift b/Sources/Data/Repositories/ScheduleRespositoryImpl.swift new file mode 100644 index 0000000..218285e --- /dev/null +++ b/Sources/Data/Repositories/ScheduleRespositoryImpl.swift @@ -0,0 +1,106 @@ +// +// ScheduleRespositoryImpl.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import RxSwift + +public class ScheduleRespositoryImpl: ScheduleRespository { + private weak var parameter: ScheduleParameterable? + private weak var recorder: (ScheduleRecordable & ExperimentRecordable)? + + public init(parameter: ScheduleParameterable, + recorder: (ScheduleRecordable & ExperimentRecordable)) { + self.parameter = parameter + self.recorder = recorder + } + + public func getValue() -> Single { + return Single.create { [weak self] single in + guard let recorder = self?.recorder else { + single(.error(RxError.noElements)) + return Disposables.create() + } + + single(.success(recorder.currentValue)) + + return Disposables.create() + } + } + + public func nextValue(_ schedule: @escaping (ScheduleParameterable, ScheduleRecordable) -> ScheduleRecordable) -> Completable { + return Completable.create { [weak self] completable in + guard + let parameter = self?.parameter, + let recorder = self?.recorder + else { + completable(.error(RxError.noElements)) + return Disposables.create() + } + + let scheduleRecorder = schedule(parameter, recorder) + recorder.currentOrder = scheduleRecorder.currentOrder + recorder.currentValue = scheduleRecorder.currentValue + completable(.completed) + + return Disposables.create() + } + } + + public func getExtendProperty() -> Single { + return Single.create { [weak self] single in + guard let recorder = self?.recorder else { + single(.error(RxError.noElements)) + return Disposables.create() + } + + single(.success(recorder.extendEntity)) + + return Disposables.create() + } + } + + public func getLastReinforcementProperty() -> Single { + return Single.create { [weak self] single in + guard let recorder = self?.recorder else { + single(.error(RxError.noElements)) + return Disposables.create() + } + + single(.success(recorder.lastReinforcementEntity)) + + return Disposables.create() + } + } + + public func clearExtendProperty() -> Completable { + return Completable.create { [weak self] completable in + guard let recorder = self?.recorder else { + completable(.error(RxError.noElements)) + return Disposables.create() + } + + recorder.extendEntity = ResponseEntity() + completable(.completed) + + return Disposables.create() + } + } + + public func updateLastReinforcementProperty(_ entity: ResponseEntity) -> Completable { + return Completable.create { [weak self] completable in + guard let recorder = self?.recorder else { + completable(.error(RxError.noElements)) + return Disposables.create() + } + + recorder.lastReinforcementEntity = entity + completable(.completed) + + return Disposables.create() + } + } + +} diff --git a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift new file mode 100644 index 0000000..00f8200 --- /dev/null +++ b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift @@ -0,0 +1,46 @@ +// +// AlternativeScheduleUseCase.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import RxSwift + +public struct AlternativeScheduleUseCase { + private var _dataStore = FixedResponseDataStore(value: 0) + public var subSchedules: Matrix + + public init(subSchedules: ScheduleUseCase...) { + self.subSchedules = Matrix(subSchedules)! + } + + public init(subSchedules: Matrix) { + self.subSchedules = subSchedules + } +} + +extension AlternativeScheduleUseCase { + public var scheduleType: ScheduleType { + return ScheduleType( + rawValue: UInt64.max, + shortName: "Alt(\(subSchedules.elements.map { $0.scheduleType.shortName }.joined(separator: ", ")))", + longName: "Alternative(\(subSchedules.elements.map { $0.scheduleType.longName }.joined(separator: ", ")))" + ) + } + +// public var dataStore: ExperimentDataStore { +// set { +// _dataStore.extendEntity = dataStore.extendEntity +// _dataStore.lastReinforcementEntity = dataStore.lastReinforcementEntity +// } +// get { +// return _dataStore +// } +// } + +// public func decision(_ observer: Observable, isAfterEffects: Bool = true) -> Observable { +//// let deicion = subSchedules.elements.map { $0.decision(observer, isAfterEffects: false) } +//// return !isAfterEffects ? decision : decision +// } +} diff --git a/Sources/Domain/UseCases/DiscreteTrialUseCaseImpl.swift b/Sources/Domain/UseCases/DiscreteTrialUseCaseImpl.swift new file mode 100644 index 0000000..ae8eda7 --- /dev/null +++ b/Sources/Domain/UseCases/DiscreteTrialUseCaseImpl.swift @@ -0,0 +1,16 @@ +// +// DiscreteTrialUseCaseImpl.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/22. +// + +import Foundation + +public struct DiscreteTrialUseCaseImpl: DiscreteTrialUseCase { + public var repository: DiscreteTrialRepository + + public init(repository: DiscreteTrialRepository) { + self.repository = repository + } +} From c292804576766f736e1af829bb359266daeed857 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Fri, 23 Nov 2018 21:41:39 +0900 Subject: [PATCH 5/9] :tada: Improve schedule use case protocols #122 --- OperantKit.xcodeproj/project.pbxproj | 76 +++-- .../Contents.swift | 268 +++++++++--------- .../Extensions/ObservableMilliseconds+.swift | 3 +- ...tResult+Rx.swift => ResultEntity+Rx.swift} | 4 +- .../Extensions/ScheduleUseCase+.swift | 110 +++---- .../Protocols/ScheduleRepository.swift | 8 +- .../Protocols/ScheduleUseCase.swift | 52 +++- .../Typealias/DecisionSchedule.swift | 2 +- .../Typealias/ReinforcementResult.swift | 10 - Sources/Common/Schedules/EXT.swift | 19 +- Sources/Common/Schedules/FI.swift | 16 +- Sources/Common/Schedules/FR.swift | 16 +- Sources/Common/Schedules/FT.swift | 14 +- Sources/Common/Schedules/RI.swift | 14 +- Sources/Common/Schedules/RR.swift | 14 +- Sources/Common/Schedules/RT.swift | 14 +- Sources/Common/Schedules/VI.swift | 14 +- Sources/Common/Schedules/VR.swift | 14 +- Sources/Common/Schedules/VT.swift | 14 +- Sources/Data/Entities/ResultEntity.swift | 23 ++ .../Data/Parameters/FixedRatioParameter.swift | 17 ++ Sources/Data/Recorders/ScheduleRecorder.swift | 29 ++ .../ScheduleRespositoryImpl.swift | 34 ++- .../UseCases/AlternativeScheduleUseCase.swift | 71 +++-- .../UseCases/ConcurrentScheduleUseCase.swift | 22 +- .../UseCases/ExtinctionScheduleUseCase.swift | 12 +- .../FixedIntervalScheduleUseCase.swift | 42 +-- .../UseCases/FixedRatioScheduleUseCase.swift | 42 +-- .../UseCases/FixedTimeScheduleUseCase.swift | 42 +-- .../RandomIntervalScheduleUseCase.swift | 42 +-- .../UseCases/RandomRatioScheduleUseCase.swift | 43 +-- .../UseCases/RandomTimeScheduleUseCase.swift | 42 +-- .../VariableIntervalScheduleUseCase.swift | 50 ++-- .../VariableRatioScheduleUseCase.swift | 49 ++-- .../VariableTimeScheduleUseCase.swift | 50 ++-- 35 files changed, 787 insertions(+), 505 deletions(-) rename Sources/Application/Extensions/{ReinforcementResult+Rx.swift => ResultEntity+Rx.swift} (93%) delete mode 100644 Sources/Application/Typealias/ReinforcementResult.swift create mode 100644 Sources/Data/Entities/ResultEntity.swift create mode 100644 Sources/Data/Parameters/FixedRatioParameter.swift create mode 100644 Sources/Data/Recorders/ScheduleRecorder.swift diff --git a/OperantKit.xcodeproj/project.pbxproj b/OperantKit.xcodeproj/project.pbxproj index 4f2881a..ae7d070 100644 --- a/OperantKit.xcodeproj/project.pbxproj +++ b/OperantKit.xcodeproj/project.pbxproj @@ -98,6 +98,18 @@ 9965658721A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; 9965658821A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; 9965658921A69410004C76F0 /* ScheduleRecordable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658521A69410004C76F0 /* ScheduleRecordable.swift */; }; + 9965658C21A8017C004C76F0 /* ResultEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658B21A8017C004C76F0 /* ResultEntity.swift */; }; + 9965658D21A8017D004C76F0 /* ResultEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658B21A8017C004C76F0 /* ResultEntity.swift */; }; + 9965658E21A8017D004C76F0 /* ResultEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658B21A8017C004C76F0 /* ResultEntity.swift */; }; + 9965658F21A8017D004C76F0 /* ResultEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965658B21A8017C004C76F0 /* ResultEntity.swift */; }; + 9965659121A82823004C76F0 /* ScheduleRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659021A82823004C76F0 /* ScheduleRecorder.swift */; }; + 9965659221A82823004C76F0 /* ScheduleRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659021A82823004C76F0 /* ScheduleRecorder.swift */; }; + 9965659321A82823004C76F0 /* ScheduleRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659021A82823004C76F0 /* ScheduleRecorder.swift */; }; + 9965659421A82823004C76F0 /* ScheduleRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659021A82823004C76F0 /* ScheduleRecorder.swift */; }; + 9965659921A8289B004C76F0 /* FixedRatioParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659821A8289B004C76F0 /* FixedRatioParameter.swift */; }; + 9965659A21A8289B004C76F0 /* FixedRatioParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659821A8289B004C76F0 /* FixedRatioParameter.swift */; }; + 9965659B21A8289B004C76F0 /* FixedRatioParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659821A8289B004C76F0 /* FixedRatioParameter.swift */; }; + 9965659C21A8289B004C76F0 /* FixedRatioParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9965659821A8289B004C76F0 /* FixedRatioParameter.swift */; }; 9998170D212C355900D9F6E5 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170B212C355900D9F6E5 /* RxCocoa.framework */; }; 9998170E212C355900D9F6E5 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170C212C355900D9F6E5 /* RxSwift.framework */; }; 99981711212C356E00D9F6E5 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9998170F212C356E00D9F6E5 /* RxSwift.framework */; }; @@ -174,8 +186,6 @@ 999C7D0D21951CDC0044C47E /* FixedEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9421951CDA0044C47E /* FixedEntity.swift */; }; 999C7D0F21951CDC0044C47E /* DecisionSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9721951CDA0044C47E /* DecisionSchedule.swift */; }; 999C7D1021951CDC0044C47E /* DecisionSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9721951CDA0044C47E /* DecisionSchedule.swift */; }; - 999C7D1221951CDC0044C47E /* ReinforcementResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9821951CDA0044C47E /* ReinforcementResult.swift */; }; - 999C7D1321951CDC0044C47E /* ReinforcementResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9821951CDA0044C47E /* ReinforcementResult.swift */; }; 999C7D1821951CDC0044C47E /* TimeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9C21951CDB0044C47E /* TimeUnit.swift */; }; 999C7D1921951CDC0044C47E /* TimeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9C21951CDB0044C47E /* TimeUnit.swift */; }; 999C7D1B21951CDC0044C47E /* Observable+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9E21951CDB0044C47E /* Observable+.swift */; }; @@ -186,8 +196,8 @@ 999C7D2221951CDC0044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; 999C7D2421951CDC0044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; 999C7D2521951CDC0044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; - 999C7D2721951CDC0044C47E /* ReinforcementResult+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ReinforcementResult+Rx.swift */; }; - 999C7D2821951CDC0044C47E /* ReinforcementResult+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ReinforcementResult+Rx.swift */; }; + 999C7D2721951CDC0044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; + 999C7D2821951CDC0044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; 999C7D2A21951CDC0044C47E /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */; }; 999C7D2B21951CDC0044C47E /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */; }; 999C7D2D21951CDC0044C47E /* ScheduleParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA521951CDB0044C47E /* ScheduleParameter.swift */; }; @@ -226,13 +236,12 @@ 999C7D91219531B80044C47E /* RxBlocking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 999C7D3921951D530044C47E /* RxBlocking.framework */; }; 999C7D92219531B80044C47E /* RxTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 999C7D3A21951D530044C47E /* RxTest.framework */; }; 999C7D93219533150044C47E /* DecisionSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9721951CDA0044C47E /* DecisionSchedule.swift */; }; - 999C7D94219533150044C47E /* ReinforcementResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9821951CDA0044C47E /* ReinforcementResult.swift */; }; 999C7D96219533150044C47E /* TimeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9C21951CDB0044C47E /* TimeUnit.swift */; }; 999C7D97219533150044C47E /* Observable+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9E21951CDB0044C47E /* Observable+.swift */; }; 999C7D98219533150044C47E /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */; }; 999C7D99219533150044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; 999C7D9A219533150044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; - 999C7D9B219533150044C47E /* ReinforcementResult+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ReinforcementResult+Rx.swift */; }; + 999C7D9B219533150044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; 999C7D9C219533150044C47E /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */; }; 999C7D9D219533150044C47E /* ScheduleParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA521951CDB0044C47E /* ScheduleParameter.swift */; }; 999C7D9E219533150044C47E /* Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA721951CDB0044C47E /* Shared.swift */; }; @@ -280,13 +289,12 @@ 999C7DCB219533300044C47E /* FleshlerHoffmanTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7D4021951F2A0044C47E /* FleshlerHoffmanTests.swift */; }; 999C7DCC219533300044C47E /* ScheduleTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7D3E21951F290044C47E /* ScheduleTypeTests.swift */; }; 999C7DE7219542610044C47E /* DecisionSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9721951CDA0044C47E /* DecisionSchedule.swift */; }; - 999C7DE8219542610044C47E /* ReinforcementResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9821951CDA0044C47E /* ReinforcementResult.swift */; }; 999C7DEA219542610044C47E /* TimeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9C21951CDB0044C47E /* TimeUnit.swift */; }; 999C7DEB219542610044C47E /* Observable+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9E21951CDB0044C47E /* Observable+.swift */; }; 999C7DEC219542610044C47E /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */; }; 999C7DED219542610044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; 999C7DEE219542610044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; - 999C7DEF219542610044C47E /* ReinforcementResult+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ReinforcementResult+Rx.swift */; }; + 999C7DEF219542610044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; 999C7DF0219542610044C47E /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */; }; 999C7DF1219542610044C47E /* ScheduleParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA521951CDB0044C47E /* ScheduleParameter.swift */; }; 999C7DF2219542610044C47E /* Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA721951CDB0044C47E /* Shared.swift */; }; @@ -498,6 +506,9 @@ 9965657B21A69128004C76F0 /* ScheduleDataStoreImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleDataStoreImpl.swift; sourceTree = ""; }; 9965658021A693AE004C76F0 /* ScheduleParameterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleParameterable.swift; sourceTree = ""; }; 9965658521A69410004C76F0 /* ScheduleRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleRecordable.swift; sourceTree = ""; }; + 9965658B21A8017C004C76F0 /* ResultEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultEntity.swift; sourceTree = ""; }; + 9965659021A82823004C76F0 /* ScheduleRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleRecorder.swift; sourceTree = ""; }; + 9965659821A8289B004C76F0 /* FixedRatioParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FixedRatioParameter.swift; sourceTree = ""; }; 9998170B212C355900D9F6E5 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/Mac/RxCocoa.framework; sourceTree = ""; }; 9998170C212C355900D9F6E5 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/Mac/RxSwift.framework; sourceTree = ""; }; 9998170F212C356E00D9F6E5 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; @@ -538,13 +549,12 @@ 999C7C9321951CDA0044C47E /* VariableEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VariableEntity.swift; sourceTree = ""; }; 999C7C9421951CDA0044C47E /* FixedEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FixedEntity.swift; sourceTree = ""; }; 999C7C9721951CDA0044C47E /* DecisionSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecisionSchedule.swift; sourceTree = ""; }; - 999C7C9821951CDA0044C47E /* ReinforcementResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReinforcementResult.swift; sourceTree = ""; }; 999C7C9C21951CDB0044C47E /* TimeUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeUnit.swift; sourceTree = ""; }; 999C7C9E21951CDB0044C47E /* Observable+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+.swift"; sourceTree = ""; }; 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Rx.swift"; sourceTree = ""; }; 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConcurrentScheduleUseCase+Shared.swift"; sourceTree = ""; }; 999C7CA121951CDB0044C47E /* ObservableType+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ObservableType+.swift"; sourceTree = ""; }; - 999C7CA221951CDB0044C47E /* ReinforcementResult+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReinforcementResult+Rx.swift"; sourceTree = ""; }; + 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ResultEntity+Rx.swift"; sourceTree = ""; }; 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Rx.swift"; sourceTree = ""; }; 999C7CA521951CDB0044C47E /* ScheduleParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduleParameter.swift; sourceTree = ""; }; 999C7CA721951CDB0044C47E /* Shared.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shared.swift; sourceTree = ""; }; @@ -747,6 +757,22 @@ name = Repositories; sourceTree = ""; }; + 9965659621A82867004C76F0 /* Parameters */ = { + isa = PBXGroup; + children = ( + 9965659821A8289B004C76F0 /* FixedRatioParameter.swift */, + ); + path = Parameters; + sourceTree = ""; + }; + 9965659721A8286D004C76F0 /* Recorders */ = { + isa = PBXGroup; + children = ( + 9965659021A82823004C76F0 /* ScheduleRecorder.swift */, + ); + path = Recorders; + sourceTree = ""; + }; 99981705212C34D100D9F6E5 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -879,6 +905,8 @@ 999C7C8821951CDA0044C47E /* Data */ = { isa = PBXGroup; children = ( + 9965659721A8286D004C76F0 /* Recorders */, + 9965659621A82867004C76F0 /* Parameters */, 999C7C8921951CDA0044C47E /* DataStores */, 999C7C8E21951CDA0044C47E /* Entities */, 9965650921A657C1004C76F0 /* Repositories */, @@ -908,6 +936,7 @@ 999C7C9221951CDA0044C47E /* RandomEntity.swift */, 999C7C9321951CDA0044C47E /* VariableEntity.swift */, 999C7C9421951CDA0044C47E /* FixedEntity.swift */, + 9965658B21A8017C004C76F0 /* ResultEntity.swift */, ); path = Entities; sourceTree = ""; @@ -928,7 +957,6 @@ isa = PBXGroup; children = ( 999C7C9721951CDA0044C47E /* DecisionSchedule.swift */, - 999C7C9821951CDA0044C47E /* ReinforcementResult.swift */, 99C7519521A07A5600DABE14 /* Times.swift */, ); path = Typealias; @@ -1033,7 +1061,7 @@ 99AE65BE21A2D3520090B308 /* Rx */ = { isa = PBXGroup; children = ( - 999C7CA221951CDB0044C47E /* ReinforcementResult+Rx.swift */, + 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */, 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */, 999C7CA121951CDB0044C47E /* ObservableType+.swift */, 999C7C9E21951CDB0044C47E /* Observable+.swift */, @@ -1519,6 +1547,7 @@ 99C7518121A06ED100DABE14 /* ScheduleUseCase+.swift in Sources */, 999C7D0F21951CDC0044C47E /* DecisionSchedule.swift in Sources */, 9965652821A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, + 9965658D21A8017D004C76F0 /* ResultEntity.swift in Sources */, 999C7CBE21951CDB0044C47E /* ScheduleType.swift in Sources */, 999C7D0C21951CDC0044C47E /* FixedEntity.swift in Sources */, 99C7519221A079A200DABE14 /* Discreteable.swift in Sources */, @@ -1536,9 +1565,9 @@ 9965656921A67898004C76F0 /* RandomRecordable.swift in Sources */, 9965658721A69410004C76F0 /* ScheduleRecordable.swift in Sources */, 99C751B021A0949A00DABE14 /* Loggable.swift in Sources */, + 9965659221A82823004C76F0 /* ScheduleRecorder.swift in Sources */, 999C7D0021951CDC0044C47E /* ResponseEntity.swift in Sources */, 99C74F0C219A77B000DABE14 /* RT.swift in Sources */, - 999C7D1221951CDC0044C47E /* ReinforcementResult.swift in Sources */, 99C751BD21A098BD00DABE14 /* Discriminateable.swift in Sources */, 999C7CEB21951CDC0044C47E /* RandomIntervalScheduleUseCase.swift in Sources */, 999C7D1E21951CDC0044C47E /* UIApplication+Rx.swift in Sources */, @@ -1557,9 +1586,10 @@ 99C74F07219A778A00DABE14 /* RandomTimeScheduleUseCase.swift in Sources */, 99C7519721A07A5600DABE14 /* Times.swift in Sources */, 9965654B21A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift in Sources */, - 999C7D2721951CDC0044C47E /* ReinforcementResult+Rx.swift in Sources */, + 999C7D2721951CDC0044C47E /* ResultEntity+Rx.swift in Sources */, 999C7D0321951CDC0044C47E /* ConcurrentEntity.swift in Sources */, 99C7530E21A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, + 9965659A21A8289B004C76F0 /* FixedRatioParameter.swift in Sources */, 99C751AB21A0949000DABE14 /* ResponseRecordable.swift in Sources */, 9965650521A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, 9965655521A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, @@ -1617,6 +1647,7 @@ 99C7531121A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, 99C7519B21A07E0300DABE14 /* TimeUnitable.swift in Sources */, 99C7530921A2C79800DABE14 /* CVDisplayLinkTimerUseCase.swift in Sources */, + 9965659121A82823004C76F0 /* ScheduleRecorder.swift in Sources */, 999C7D1921951CDC0044C47E /* TimeUnit.swift in Sources */, 999C7CFE21951CDC0044C47E /* ExperimentEntity.swift in Sources */, 999C7CAD21951CDB0044C47E /* RI.swift in Sources */, @@ -1646,6 +1677,7 @@ 9965658121A693AE004C76F0 /* ScheduleParameterable.swift in Sources */, 99C7519121A079A200DABE14 /* Discreteable.swift in Sources */, 99C752FD21A2C68A00DABE14 /* TimerUseCase.swift in Sources */, + 9965658C21A8017C004C76F0 /* ResultEntity.swift in Sources */, 99AE65C021A2D6130090B308 /* Continuable.swift in Sources */, 999C7D0D21951CDC0044C47E /* FixedEntity.swift in Sources */, 9965649F21A4FBCA004C76F0 /* ObservableMilliseconds+.swift in Sources */, @@ -1664,7 +1696,6 @@ 9965655E21A67765004C76F0 /* VariableRecordable.swift in Sources */, 99C751BC21A098BD00DABE14 /* Discriminateable.swift in Sources */, 99C74EFA219A761000DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, - 999C7D1321951CDC0044C47E /* ReinforcementResult.swift in Sources */, 999C7CEC21951CDC0044C47E /* RandomIntervalScheduleUseCase.swift in Sources */, 999C7D1F21951CDC0044C47E /* UIApplication+Rx.swift in Sources */, 9965654221A66BA9004C76F0 /* DiscreteTrialUseCase.swift in Sources */, @@ -1676,7 +1707,8 @@ 99C751A521A0933800DABE14 /* ExperimentRecordable.swift in Sources */, 999C7CEF21951CDC0044C47E /* VariableIntervalScheduleUseCase.swift in Sources */, 99C7519621A07A5600DABE14 /* Times.swift in Sources */, - 999C7D2821951CDC0044C47E /* ReinforcementResult+Rx.swift in Sources */, + 9965659921A8289B004C76F0 /* FixedRatioParameter.swift in Sources */, + 999C7D2821951CDC0044C47E /* ResultEntity+Rx.swift in Sources */, 9965657C21A69128004C76F0 /* ScheduleDataStoreImpl.swift in Sources */, 9965652721A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, 999C7D0421951CDC0044C47E /* ConcurrentEntity.swift in Sources */, @@ -1734,7 +1766,6 @@ files = ( 9965657421A67D2D004C76F0 /* ScheduleRepository.swift in Sources */, 999C7D93219533150044C47E /* DecisionSchedule.swift in Sources */, - 999C7D94219533150044C47E /* ReinforcementResult.swift in Sources */, 99C7531321A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, 99C7519D21A07E0300DABE14 /* TimeUnitable.swift in Sources */, 99C7530B21A2C79800DABE14 /* CVDisplayLinkTimerUseCase.swift in Sources */, @@ -1744,7 +1775,7 @@ 999C7D99219533150044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7D9A219533150044C47E /* ObservableType+.swift in Sources */, 99C7518921A077AB00DABE14 /* Responsible.swift in Sources */, - 999C7D9B219533150044C47E /* ReinforcementResult+Rx.swift in Sources */, + 999C7D9B219533150044C47E /* ResultEntity+Rx.swift in Sources */, 999C7D9C219533150044C47E /* UIViewController+Rx.swift in Sources */, 99C752F521A2C64E00DABE14 /* Priority.swift in Sources */, 9965655121A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */, @@ -1760,6 +1791,7 @@ 999C7DA1219533150044C47E /* RI.swift in Sources */, 999C7DA2219533150044C47E /* FI.swift in Sources */, 9965652921A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, + 9965658E21A8017D004C76F0 /* ResultEntity.swift in Sources */, 999C7DA3219533150044C47E /* FR.swift in Sources */, 999C7DA4219533150044C47E /* EXT.swift in Sources */, 99C7519321A079A200DABE14 /* Discreteable.swift in Sources */, @@ -1778,6 +1810,7 @@ 9965658821A69410004C76F0 /* ScheduleRecordable.swift in Sources */, 99C751B121A0949A00DABE14 /* Loggable.swift in Sources */, 999C7DAA219533150044C47E /* SessionEvents.swift in Sources */, + 9965659321A82823004C76F0 /* ScheduleRecorder.swift in Sources */, 99C74F0B219A77AF00DABE14 /* RT.swift in Sources */, 999C7DAD219533150044C47E /* FleshlerHoffman.swift in Sources */, 99C751BE21A098BD00DABE14 /* Discriminateable.swift in Sources */, @@ -1801,6 +1834,7 @@ 99C7519821A07A5600DABE14 /* Times.swift in Sources */, 999C7DB4219533150044C47E /* ConcurrentEntity.swift in Sources */, 99C7530F21A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, + 9965659B21A8289B004C76F0 /* FixedRatioParameter.swift in Sources */, 99C74EFC219A761500DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, 9965650621A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, 9965655621A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, @@ -1854,7 +1888,6 @@ files = ( 9965657521A67D2D004C76F0 /* ScheduleRepository.swift in Sources */, 999C7DE7219542610044C47E /* DecisionSchedule.swift in Sources */, - 999C7DE8219542610044C47E /* ReinforcementResult.swift in Sources */, 99C7531421A2C79800DABE14 /* CADisplayLinkTimerUseCase.swift in Sources */, 99C7519E21A07E0300DABE14 /* TimeUnitable.swift in Sources */, 99C7530C21A2C79800DABE14 /* CVDisplayLinkTimerUseCase.swift in Sources */, @@ -1864,7 +1897,7 @@ 999C7DED219542610044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7DEE219542610044C47E /* ObservableType+.swift in Sources */, 99C7518A21A077AB00DABE14 /* Responsible.swift in Sources */, - 999C7DEF219542610044C47E /* ReinforcementResult+Rx.swift in Sources */, + 999C7DEF219542610044C47E /* ResultEntity+Rx.swift in Sources */, 999C7DF0219542610044C47E /* UIViewController+Rx.swift in Sources */, 99C752F621A2C64E00DABE14 /* Priority.swift in Sources */, 9965655221A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift in Sources */, @@ -1880,6 +1913,7 @@ 999C7DF5219542610044C47E /* RI.swift in Sources */, 999C7DF6219542610044C47E /* FI.swift in Sources */, 9965652A21A6597C004C76F0 /* DiscreteTrialRecordable.swift in Sources */, + 9965658F21A8017D004C76F0 /* ResultEntity.swift in Sources */, 999C7DF7219542610044C47E /* FR.swift in Sources */, 999C7DF8219542610044C47E /* EXT.swift in Sources */, 99C7519421A079A200DABE14 /* Discreteable.swift in Sources */, @@ -1898,6 +1932,7 @@ 9965658921A69410004C76F0 /* ScheduleRecordable.swift in Sources */, 99C751B221A0949A00DABE14 /* Loggable.swift in Sources */, 999C7DFE219542610044C47E /* SessionEvents.swift in Sources */, + 9965659421A82823004C76F0 /* ScheduleRecorder.swift in Sources */, 99C74F0A219A77AE00DABE14 /* RT.swift in Sources */, 999C7E01219542610044C47E /* FleshlerHoffman.swift in Sources */, 99C751BF21A098BD00DABE14 /* Discriminateable.swift in Sources */, @@ -1921,6 +1956,7 @@ 99C7519921A07A5600DABE14 /* Times.swift in Sources */, 999C7E08219542610044C47E /* ConcurrentEntity.swift in Sources */, 99C7531021A2C79800DABE14 /* WhileLoopTimerUseCase.swift in Sources */, + 9965659C21A8289B004C76F0 /* FixedRatioParameter.swift in Sources */, 99C74EFD219A761600DABE14 /* FixedTimeScheduleUseCase.swift in Sources */, 9965650721A64784004C76F0 /* AlternativeScheduleUseCase.swift in Sources */, 9965655721A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift in Sources */, diff --git a/OperantKitPlayground.playground/Contents.swift b/OperantKitPlayground.playground/Contents.swift index 825192d..534e21f 100644 --- a/OperantKitPlayground.playground/Contents.swift +++ b/OperantKitPlayground.playground/Contents.swift @@ -3,137 +3,145 @@ import RxCocoa import RxSwift func builder() { - let useCase: DiscreteTrialUseCase = DiscreteTrialUseCaseImpl( - repository: DiscreteTrialRepositoryImpl( - dataStore: DiscreteTrialDataStoreImpl( - maxTrials: 2, - parameters: [], - records: [] - ) + let useCase: FixedRatioScheduleUseCase = FixedRatioScheduleUseCase( + repository: ScheduleRespositoryImpl( + dataStore: ScheduleDataStoreImpl(value: 5) ) ) } -let numberOfPairings: Int = 80 -let whiteKeyLightDuration: Seconds = 8 -let trayOperatingDuration: Milliseconds = 4000 -let interTrialInterval: [Seconds] = [Seconds](5...10) // (30...90) - .filter({ $0 % 5 == 0 }) - .map { TimeUnit.seconds.milliseconds($0) } - .shuffled() - -var nextInterval: Milliseconds = 0 -var currentOrder: Int = 0 -func updateInterval() { - nextInterval = interTrialInterval[currentOrder % interTrialInterval.count] -} - -let timer = WhileLoopTimerUseCase(priority: .high) -let fixedTimeSchedule = FT(whiteKeyLightDuration) -let continuousReinforcementSchedule = CRF() -let responseAction = PublishSubject() -let startTimerAction = PublishSubject() -let finishTimerAction = PublishSubject() -var isSessionFlag = true -let duringSR = BehaviorRelay(value: false) -var disposeBag = DisposeBag() - -let respnseObservable = responseAction.response(timer) - .do(onNext: { print("Response: \($0.numOfResponses), \($0.milliseconds)ms") }) - -let milliseconds = timer.milliseconds.shared - .filter({ $0 % 1000 == 0 }) - -let firstStart = milliseconds.take(1) - -firstStart - .do(onNext: { _ in print("Session started") }) - .subscribe() - .disposed(by: disposeBag) - -let timeObservable = milliseconds - .do(onNext: { print("Time elapsed: \($0)ms") }) - .map { ResponseEntity(numOfResponses: 0, milliseconds: $0) } - .share(replay: 1) - -let reinforcementOn = Observable.merge( - fixedTimeSchedule.decision(timeObservable), - continuousReinforcementSchedule.decision(respnseObservable) - ) - .filter({ _ in !duringSR.value }) - .filter({ $0.isReinforcement }) - .share(replay: 1) - -let reinforcementOff = reinforcementOn - .do(onNext: { print("SR on: \($0.entity.milliseconds)ms (IRI: \(trayOperatingDuration)ms)") }) - .storeResponse(fixedTimeSchedule.dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) - .extend(time: trayOperatingDuration, entities: fixedTimeSchedule.extendEntity) - .flatMap { timer.delay(trayOperatingDuration, currentTime: $0.entity.milliseconds) } - .do(onNext: { print("SR off: \($0)ms") }) - .asObservable() - .share(replay: 1) - -let nextTrial = Observable.merge( - firstStart, - reinforcementOff - ) - .do(onNext: { _ in updateInterval() }) - .do(onNext: { print("ITI on: \($0)ms (Next ITI: \(nextInterval)ms)") }) - .extend(time: { nextInterval }, entities: fixedTimeSchedule.extendEntity) - .flatMap { timer.delay(nextInterval, currentTime: $0) } - .do(onNext: { print("ITI off: \($0)ms") }) - .asObservable() - .share(replay: 1) - -nextTrial - .do(onNext: { _ in print("SD on") }) - .subscribe() - .disposed(by: disposeBag) - -reinforcementOn - .do(onNext: { _ in print("SD off") }) - .subscribe() - .disposed(by: disposeBag) - -reinforcementOff - .count() - .do(onNext: { print("Trial \($0)/\(numberOfPairings) finished") }) - .filter({ $0 >= numberOfPairings }) - .mapToVoid() - .bind(to: finishTimerAction) - .disposed(by: disposeBag) - -Observable.merge( - reinforcementOn.map { _ in true }, - reinforcementOff.map { _ in false } - ) - .bind(to: duringSR) - .disposed(by: disposeBag) - -startTimerAction - .flatMap { timer.start() } - .subscribe() - .disposed(by: disposeBag) - -finishTimerAction - .flatMap { timer.finish() } - .do(onNext: { print("Session finished: \($0)ms") }) - .do(onNext: { _ in print("Program ended if enter any keys") }) - .mapToVoid() - .subscribe(onNext: { - isSessionFlag = false - disposeBag = DisposeBag() - }) - .disposed(by: disposeBag) - -startTimerAction.onNext(()) -while isSessionFlag { - let input = readLine() - guard isSessionFlag else { continue } - switch input { - case "q": - finishTimerAction.onNext(()) - default: - responseAction.onNext(()) - } -} +//func builder() { +// let useCase: DiscreteTrialUseCase = DiscreteTrialUseCaseImpl( +// repository: DiscreteTrialRepositoryImpl( +// dataStore: DiscreteTrialDataStoreImpl( +// maxTrials: 2, +// parameters: [], +// records: [] +// ) +// ) +// ) +//} +// +//let numberOfPairings: Int = 80 +//let whiteKeyLightDuration: Seconds = 8 +//let trayOperatingDuration: Milliseconds = 4000 +//let interTrialInterval: [Seconds] = [Seconds](5...10) // (30...90) +// .filter({ $0 % 5 == 0 }) +// .map { TimeUnit.seconds.milliseconds($0) } +// .shuffled() +// +//var nextInterval: Milliseconds = 0 +//var currentOrder: Int = 0 +//func updateInterval() { +// nextInterval = interTrialInterval[currentOrder % interTrialInterval.count] +//} +// +//let timer = WhileLoopTimerUseCase(priority: .high) +//let fixedTimeSchedule = FT(whiteKeyLightDuration) +//let continuousReinforcementSchedule = CRF() +//let responseAction = PublishSubject() +//let startTimerAction = PublishSubject() +//let finishTimerAction = PublishSubject() +//var isSessionFlag = true +//let duringSR = BehaviorRelay(value: false) +//var disposeBag = DisposeBag() +// +//let respnseObservable = responseAction.response(timer) +// .do(onNext: { print("Response: \($0.numOfResponses), \($0.milliseconds)ms") }) +// +//let milliseconds = timer.milliseconds.shared +// .filter({ $0 % 1000 == 0 }) +// +//let firstStart = milliseconds.take(1) +// +//firstStart +// .do(onNext: { _ in print("Session started") }) +// .subscribe() +// .disposed(by: disposeBag) +// +//let timeObservable = milliseconds +// .do(onNext: { print("Time elapsed: \($0)ms") }) +// .map { ResponseEntity(numOfResponses: 0, milliseconds: $0) } +// .share(replay: 1) +// +//let reinforcementOn = Observable.merge( +// fixedTimeSchedule.decision(timeObservable), +// continuousReinforcementSchedule.decision(respnseObservable) +// ) +// .filter({ _ in !duringSR.value }) +// .filter({ $0.isReinforcement }) +// .share(replay: 1) +// +//let reinforcementOff = reinforcementOn +// .do(onNext: { print("SR on: \($0.entity.milliseconds)ms (IRI: \(trayOperatingDuration)ms)") }) +// .storeResponse(fixedTimeSchedule.dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) +// .extend(time: trayOperatingDuration, entities: fixedTimeSchedule.extendEntity) +// .flatMap { timer.delay(trayOperatingDuration, currentTime: $0.entity.milliseconds) } +// .do(onNext: { print("SR off: \($0)ms") }) +// .asObservable() +// .share(replay: 1) +// +//let nextTrial = Observable.merge( +// firstStart, +// reinforcementOff +// ) +// .do(onNext: { _ in updateInterval() }) +// .do(onNext: { print("ITI on: \($0)ms (Next ITI: \(nextInterval)ms)") }) +// .extend(time: { nextInterval }, entities: fixedTimeSchedule.extendEntity) +// .flatMap { timer.delay(nextInterval, currentTime: $0) } +// .do(onNext: { print("ITI off: \($0)ms") }) +// .asObservable() +// .share(replay: 1) +// +//nextTrial +// .do(onNext: { _ in print("SD on") }) +// .subscribe() +// .disposed(by: disposeBag) +// +//reinforcementOn +// .do(onNext: { _ in print("SD off") }) +// .subscribe() +// .disposed(by: disposeBag) +// +//reinforcementOff +// .count() +// .do(onNext: { print("Trial \($0)/\(numberOfPairings) finished") }) +// .filter({ $0 >= numberOfPairings }) +// .mapToVoid() +// .bind(to: finishTimerAction) +// .disposed(by: disposeBag) +// +//Observable.merge( +// reinforcementOn.map { _ in true }, +// reinforcementOff.map { _ in false } +// ) +// .bind(to: duringSR) +// .disposed(by: disposeBag) +// +//startTimerAction +// .flatMap { timer.start() } +// .subscribe() +// .disposed(by: disposeBag) +// +//finishTimerAction +// .flatMap { timer.finish() } +// .do(onNext: { print("Session finished: \($0)ms") }) +// .do(onNext: { _ in print("Program ended if enter any keys") }) +// .mapToVoid() +// .subscribe(onNext: { +// isSessionFlag = false +// disposeBag = DisposeBag() +// }) +// .disposed(by: disposeBag) +// +//startTimerAction.onNext(()) +//while isSessionFlag { +// let input = readLine() +// guard isSessionFlag else { continue } +// switch input { +// case "q": +// finishTimerAction.onNext(()) +// default: +// responseAction.onNext(()) +// } +//} diff --git a/Sources/Application/Extensions/ObservableMilliseconds+.swift b/Sources/Application/Extensions/ObservableMilliseconds+.swift index 871f3c1..92c6c34 100644 --- a/Sources/Application/Extensions/ObservableMilliseconds+.swift +++ b/Sources/Application/Extensions/ObservableMilliseconds+.swift @@ -15,8 +15,7 @@ public extension Observable where E == Milliseconds { /// Delay timer with entities func delay(_ timer: TimerUseCase, time: @escaping () -> Int, entities: [ResponseEntity] = []) -> Observable { - return self - .extend(time: time, entities: entities) + return extend(time: time, entities: entities) .flatMap { timer.delay(time(), currentTime: $0) } } } diff --git a/Sources/Application/Extensions/ReinforcementResult+Rx.swift b/Sources/Application/Extensions/ResultEntity+Rx.swift similarity index 93% rename from Sources/Application/Extensions/ReinforcementResult+Rx.swift rename to Sources/Application/Extensions/ResultEntity+Rx.swift index a652f19..767ea5b 100644 --- a/Sources/Application/Extensions/ReinforcementResult+Rx.swift +++ b/Sources/Application/Extensions/ResultEntity+Rx.swift @@ -1,5 +1,5 @@ // -// ReinforcementResult+Rx.swift +// ResultEntity+Rx.swift // OperantKit // // Created by Yuto Mizutani on 2018/10/31. @@ -8,7 +8,7 @@ import RxSwift -public extension Observable where E == ReinforcementResult { +public extension Observable where E == ResultEntity { func clearResponse(_ entity: ResponseEntity, condition: @escaping ((E) -> Bool)) -> Observable { return self.do(onNext: { guard condition($0) else { return } diff --git a/Sources/Application/Extensions/ScheduleUseCase+.swift b/Sources/Application/Extensions/ScheduleUseCase+.swift index e9ba6a7..cd7a1cb 100644 --- a/Sources/Application/Extensions/ScheduleUseCase+.swift +++ b/Sources/Application/Extensions/ScheduleUseCase+.swift @@ -7,58 +7,60 @@ import Foundation -public func EXT() -> ExtinctionScheduleUseCase { - return ExtinctionScheduleUseCase() -} +// TODO: Add empty DataStore and Repository -public func CRF() -> FixedRatioScheduleUseCase { - return FixedRatioScheduleUseCase(value: 1) -} - -public func FR(_ value: Int) -> FixedRatioScheduleUseCase { - return FixedRatioScheduleUseCase(value: value) -} - -public func VR(_ value: Int, iterations: Int = 12) -> VariableRatioScheduleUseCase { - return VariableRatioScheduleUseCase(value: value, iterations: iterations) -} - -public func VR(_ value: Int, values: [Int]) -> VariableRatioScheduleUseCase { - return VariableRatioScheduleUseCase(value: value, values: values) -} - -public func RR(_ value: Int) -> RandomRatioScheduleUseCase { - return RandomRatioScheduleUseCase(value: value) -} - -public func FI(_ value: Int, unit: TimeUnit = .seconds) -> FixedIntervalScheduleUseCase { - return FixedIntervalScheduleUseCase(value: value, unit: unit) -} - -public func VI(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableIntervalScheduleUseCase { - return VariableIntervalScheduleUseCase(value: value, unit: unit, iterations: iterations) -} - -public func RI(_ value: Int, unit: TimeUnit = .seconds) -> RandomIntervalScheduleUseCase { - return RandomIntervalScheduleUseCase(value: value, unit: unit) -} - -public func FT(_ value: Int, unit: TimeUnit = .seconds) -> FixedTimeScheduleUseCase { - return FixedTimeScheduleUseCase(value: value, unit: unit) -} - -public func VT(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableTimeScheduleUseCase { - return VariableTimeScheduleUseCase(value: value, unit: unit, iterations: iterations) -} - -public func RT(_ value: Int, unit: TimeUnit = .seconds) -> RandomTimeScheduleUseCase { - return RandomTimeScheduleUseCase(value: value, unit: unit) -} - -public func Conc(_ subSchedules: ScheduleUseCase...) -> ConcurrentScheduleUseCase { - return ConcurrentScheduleUseCase(subSchedules: subSchedules, isShared: false) -} - -public func Conc(_ sharedSchedule: Shared) -> ConcurrentScheduleUseCase { - return ConcurrentScheduleUseCase(sharedSchedule) -} +//public func EXT() -> ExtinctionScheduleUseCase { +// return ExtinctionScheduleUseCase() +//} +// +//public func CRF() -> FixedRatioScheduleUseCase { +// return FixedRatioScheduleUseCase(value: 1) +//} +// +//public func FR(_ value: Int) -> FixedRatioScheduleUseCase { +// return FixedRatioScheduleUseCase(value: value) +//} +// +//public func VR(_ value: Int, iterations: Int = 12) -> VariableRatioScheduleUseCase { +// return VariableRatioScheduleUseCase(value: value, iterations: iterations) +//} +// +//public func VR(_ value: Int, values: [Int]) -> VariableRatioScheduleUseCase { +// return VariableRatioScheduleUseCase(value: value, values: values) +//} +// +//public func RR(_ value: Int) -> RandomRatioScheduleUseCase { +// return RandomRatioScheduleUseCase(value: value) +//} +// +//public func FI(_ value: Int, unit: TimeUnit = .seconds) -> FixedIntervalScheduleUseCase { +// return FixedIntervalScheduleUseCase(value: value, unit: unit) +//} +// +//public func VI(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableIntervalScheduleUseCase { +// return VariableIntervalScheduleUseCase(value: value, unit: unit, iterations: iterations) +//} +// +//public func RI(_ value: Int, unit: TimeUnit = .seconds) -> RandomIntervalScheduleUseCase { +// return RandomIntervalScheduleUseCase(value: value, unit: unit) +//} +// +//public func FT(_ value: Int, unit: TimeUnit = .seconds) -> FixedTimeScheduleUseCase { +// return FixedTimeScheduleUseCase(value: value, unit: unit) +//} +// +//public func VT(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableTimeScheduleUseCase { +// return VariableTimeScheduleUseCase(value: value, unit: unit, iterations: iterations) +//} +// +//public func RT(_ value: Int, unit: TimeUnit = .seconds) -> RandomTimeScheduleUseCase { +// return RandomTimeScheduleUseCase(value: value, unit: unit) +//} +// +//public func Conc(_ subSchedules: ScheduleUseCase...) -> ConcurrentScheduleUseCase { +// return ConcurrentScheduleUseCase(subSchedules: subSchedules, isShared: false) +//} +// +//public func Conc(_ sharedSchedule: Shared) -> ConcurrentScheduleUseCase { +// return ConcurrentScheduleUseCase(sharedSchedule) +//} diff --git a/Sources/Application/Protocols/ScheduleRepository.swift b/Sources/Application/Protocols/ScheduleRepository.swift index ca25e10..89550fe 100644 --- a/Sources/Application/Protocols/ScheduleRepository.swift +++ b/Sources/Application/Protocols/ScheduleRepository.swift @@ -7,11 +7,11 @@ import RxSwift -public protocol ScheduleRespository { +public protocol ScheduleRespository: class { func getValue() -> Single - func nextValue(_: @escaping (ScheduleParameterable, ScheduleRecordable) -> ScheduleRecordable) -> Completable + func nextValue(_: @escaping (ScheduleParameterable, ScheduleRecordable) -> ScheduleRecordable) -> Single<()> func getExtendProperty() -> Single func getLastReinforcementProperty() -> Single - func clearExtendProperty() -> Completable - func updateLastReinforcementProperty(_:ResponseEntity) -> Completable + func clearExtendProperty() -> Single<()> + func updateLastReinforcementProperty(_:ResponseEntity) -> Single<()> } diff --git a/Sources/Application/Protocols/ScheduleUseCase.swift b/Sources/Application/Protocols/ScheduleUseCase.swift index 4a95171..bda1e22 100644 --- a/Sources/Application/Protocols/ScheduleUseCase.swift +++ b/Sources/Application/Protocols/ScheduleUseCase.swift @@ -8,8 +8,56 @@ import RxSwift public protocol ScheduleUseCase { + var repository: ScheduleRespository? { get } var scheduleType: ScheduleType { get } - var extendEntity: ResponseEntity { get } - func decision(_: Observable) -> Observable + /// Decision the reinforcement schedule + func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable + func updateValue(_ observer: Observable) -> Observable +} + +public extension ScheduleUseCase { + func updateValue(_ observer: Observable) -> Observable { + switch scheduleType { + case let s where s.hasVariableSchedule(): + return observer + .flatMap { observer -> Observable in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.clearExtendProperty().asObservable(), + repository.updateLastReinforcementProperty(observer.entity).asObservable(), + repository.nextValue({ + $1.currentOrder += 1 + $1.currentValue = $0.values[$1.currentOrder % $0.values.count] + return $1 + }).asObservable() + ) + .map { _ in observer } + } + case let s where s.hasRandomSchedule(): + return observer + .flatMap { observer -> Observable in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.clearExtendProperty().asObservable(), + repository.updateLastReinforcementProperty(observer.entity).asObservable(), + repository.nextValue({ + $1.currentValue = $0.value > 0 ? Int.random(in: 1...$0.value) : 1 + return $1 + }).asObservable() + ) + .map { _ in observer } + } + default: + return observer + .flatMap { observer -> Observable in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.clearExtendProperty().asObservable(), + repository.updateLastReinforcementProperty(observer.entity).asObservable() + ) + .map { _ in observer } + } + } + } } diff --git a/Sources/Application/Typealias/DecisionSchedule.swift b/Sources/Application/Typealias/DecisionSchedule.swift index 8f373e5..cf25414 100644 --- a/Sources/Application/Typealias/DecisionSchedule.swift +++ b/Sources/Application/Typealias/DecisionSchedule.swift @@ -7,4 +7,4 @@ import RxSwift -public typealias DecisionSchedule = ((Observable) -> Observable) +public typealias DecisionSchedule = ((Observable) -> Observable) diff --git a/Sources/Application/Typealias/ReinforcementResult.swift b/Sources/Application/Typealias/ReinforcementResult.swift deleted file mode 100644 index ac2bfbc..0000000 --- a/Sources/Application/Typealias/ReinforcementResult.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// ReinforcementResult.swift -// OperantKit -// -// Created by Yuto Mizutani on 2018/11/01. -// - -import Foundation - -public typealias ReinforcementResult = (isReinforcement: Bool, entity: ResponseEntity) diff --git a/Sources/Common/Schedules/EXT.swift b/Sources/Common/Schedules/EXT.swift index e9c3748..ac91e22 100644 --- a/Sources/Common/Schedules/EXT.swift +++ b/Sources/Common/Schedules/EXT.swift @@ -9,14 +9,23 @@ import RxSwift extension Observable where E == ResponseEntity { + /// Fixed interval schedule + public func EXT(_ value: Single) -> Observable { + return extinction(value) + } + + /// FI logic + func extinction(_ value: Single) -> Observable { + return map { _ in false } + } + /// Extinction schedule - public func EXT() -> Observable { - return self - .extinction() + public func EXT() -> Observable { + return extinction() } /// EXT logic - func extinction() -> Observable { - return self.map { (false, $0) } + func extinction() -> Observable { + return map { ResultEntity(false, $0) } } } diff --git a/Sources/Common/Schedules/FI.swift b/Sources/Common/Schedules/FI.swift index 5edb687..3d1a127 100644 --- a/Sources/Common/Schedules/FI.swift +++ b/Sources/Common/Schedules/FI.swift @@ -10,15 +10,25 @@ import RxSwift extension Observable where E == ResponseEntity { /// Fixed interval schedule - public func FI(_ value: Milliseconds, with entities: E...) -> Observable { + public func FI(_ value: Single) -> Observable { + return fixedInterval(value) + } + + /// FI logic + func fixedInterval(_ value: Single) -> Observable { + return flatMap { a in value.map { a.milliseconds >= $0 } } + } + + /// Fixed interval schedule + public func FI(_ value: Milliseconds, with entities: E...) -> Observable { return self .fixedInterval(value, entities) } /// FI logic - func fixedInterval(_ value: Milliseconds, _ entities: [E]) -> Observable { + func fixedInterval(_ value: Milliseconds, _ entities: [E]) -> Observable { return self.map { - ($0.milliseconds >= value + entities.map { $0.milliseconds }.reduce(0) { $0 + $1 }, $0) + ResultEntity($0.milliseconds >= value + entities.map { $0.milliseconds }.reduce(0) { $0 + $1 }, $0) } } } diff --git a/Sources/Common/Schedules/FR.swift b/Sources/Common/Schedules/FR.swift index 37d3db4..f7d15da 100644 --- a/Sources/Common/Schedules/FR.swift +++ b/Sources/Common/Schedules/FR.swift @@ -10,15 +10,25 @@ import RxSwift extension Observable where E == ResponseEntity { /// Fixed ratio schedule - public func FR(_ value: Int, with entities: E...) -> Observable { + public func FR(_ value: Single) -> Observable { + return fixedRatio(value) + } + + /// FR logic + func fixedRatio(_ value: Single) -> Observable { + return flatMap { a in value.map { a.numOfResponses >= $0 } } + } + + /// Fixed ratio schedule + public func FR(_ value: Int, with entities: E...) -> Observable { return self .fixedRatio(value, entities) } /// FR logic - func fixedRatio(_ value: Int, _ entities: [E]) -> Observable { + func fixedRatio(_ value: Int, _ entities: [E]) -> Observable { return self.map { - (($0.numOfResponses >= value + entities.map { $0.numOfResponses }.reduce(0) { $0 + $1 }), $0) + ResultEntity(($0.numOfResponses >= value + entities.map { $0.numOfResponses }.reduce(0) { $0 + $1 }), $0) } } } diff --git a/Sources/Common/Schedules/FT.swift b/Sources/Common/Schedules/FT.swift index 98dd266..fe333a9 100644 --- a/Sources/Common/Schedules/FT.swift +++ b/Sources/Common/Schedules/FT.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Fixed time schedule - public func FT(_ value: Milliseconds, with entities: E...) -> Observable { + public func FT(_ value: Single) -> Observable { + return fixedTime(value) + } + + /// FT logic + func fixedTime(_ value: Single) -> Observable { + return fixedInterval(value) + } + + /// Fixed time schedule + public func FT(_ value: Milliseconds, with entities: E...) -> Observable { return self .fixedTime(value, entities) } /// FT logic - func fixedTime(_ value: Milliseconds, _ entities: [E]) -> Observable { + func fixedTime(_ value: Milliseconds, _ entities: [E]) -> Observable { return self.fixedInterval(value, entities) } } diff --git a/Sources/Common/Schedules/RI.swift b/Sources/Common/Schedules/RI.swift index 3775131..2d861e2 100644 --- a/Sources/Common/Schedules/RI.swift +++ b/Sources/Common/Schedules/RI.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Random interval schedule - public func RI(_ value: Milliseconds, with entities: E...) -> Observable { + public func RI(_ value: Single) -> Observable { + return randomInterval(value) + } + + /// RI logic + func randomInterval(_ value: Single) -> Observable { + return fixedInterval(value) + } + + /// Random interval schedule + public func RI(_ value: Milliseconds, with entities: E...) -> Observable { return self .randomInterval(value, entities) } /// RI logic - func randomInterval(_ value: Milliseconds, _ entities: [E]) -> Observable { + func randomInterval(_ value: Milliseconds, _ entities: [E]) -> Observable { return self.fixedInterval(value, entities) } } diff --git a/Sources/Common/Schedules/RR.swift b/Sources/Common/Schedules/RR.swift index e065f35..cba9303 100644 --- a/Sources/Common/Schedules/RR.swift +++ b/Sources/Common/Schedules/RR.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Random ratio schedule - public func RR(_ value: Int, with entities: E...) -> Observable { + public func RR(_ value: Single) -> Observable { + return randomRatio(value) + } + + /// RR logic + func randomRatio(_ value: Single) -> Observable { + return fixedRatio(value) + } + + /// Random ratio schedule + public func RR(_ value: Int, with entities: E...) -> Observable { return self .randomRatio(value, entities) } /// RR logic - func randomRatio(_ value: Int, _ entities: [E]) -> Observable { + func randomRatio(_ value: Int, _ entities: [E]) -> Observable { return fixedRatio(value, entities) } } diff --git a/Sources/Common/Schedules/RT.swift b/Sources/Common/Schedules/RT.swift index bb2c7a7..502e2bd 100644 --- a/Sources/Common/Schedules/RT.swift +++ b/Sources/Common/Schedules/RT.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Random time schedule - public func RT(_ value: Milliseconds, with entities: E...) -> Observable { + public func RT(_ value: Single) -> Observable { + return randomTime(value) + } + + /// RT logic + func randomTime(_ value: Single) -> Observable { + return fixedInterval(value) + } + + /// Random time schedule + public func RT(_ value: Milliseconds, with entities: E...) -> Observable { return self .randomTime(value, entities) } /// RT logic - func randomTime(_ value: Milliseconds, _ entities: [E]) -> Observable { + func randomTime(_ value: Milliseconds, _ entities: [E]) -> Observable { return self.fixedTime(value, entities) } } diff --git a/Sources/Common/Schedules/VI.swift b/Sources/Common/Schedules/VI.swift index 0b1b14f..99e7346 100644 --- a/Sources/Common/Schedules/VI.swift +++ b/Sources/Common/Schedules/VI.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Variable interval schedule - public func VI(_ value: Milliseconds, with entities: E...) -> Observable { + public func VI(_ value: Single) -> Observable { + return variableInterval(value) + } + + /// VI logic + func variableInterval(_ value: Single) -> Observable { + return fixedInterval(value) + } + + /// Variable interval schedule + public func VI(_ value: Milliseconds, with entities: E...) -> Observable { return self .variableInterval(value, entities) } /// VI logic - func variableInterval(_ value: Milliseconds, _ entities: [E]) -> Observable { + func variableInterval(_ value: Milliseconds, _ entities: [E]) -> Observable { return self.fixedInterval(value, entities) } } diff --git a/Sources/Common/Schedules/VR.swift b/Sources/Common/Schedules/VR.swift index 39472e4..d6397df 100644 --- a/Sources/Common/Schedules/VR.swift +++ b/Sources/Common/Schedules/VR.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Variable ratio schedule - public func VR(_ value: Int, with entities: E...) -> Observable { + public func VR(_ value: Single) -> Observable { + return variableRatio(value) + } + + /// VR logic + func variableRatio(_ value: Single) -> Observable { + return fixedRatio(value) + } + + /// Variable ratio schedule + public func VR(_ value: Int, with entities: E...) -> Observable { return self .variableRatio(value, entities) } /// VR logic - func variableRatio(_ value: Int, _ entities: [E]) -> Observable { + func variableRatio(_ value: Int, _ entities: [E]) -> Observable { return fixedRatio(value, entities) } } diff --git a/Sources/Common/Schedules/VT.swift b/Sources/Common/Schedules/VT.swift index b370e53..820cd56 100644 --- a/Sources/Common/Schedules/VT.swift +++ b/Sources/Common/Schedules/VT.swift @@ -10,13 +10,23 @@ import RxSwift extension Observable where E == ResponseEntity { /// Variable time schedule - public func VT(_ value: Milliseconds, with entities: E...) -> Observable { + public func VT(_ value: Single) -> Observable { + return variableTime(value) + } + + /// VT logic + func variableTime(_ value: Single) -> Observable { + return fixedInterval(value) + } + + /// Variable time schedule + public func VT(_ value: Milliseconds, with entities: E...) -> Observable { return self .variableTime(value, entities) } /// VT logic - func variableTime(_ value: Milliseconds, _ entities: [E]) -> Observable { + func variableTime(_ value: Milliseconds, _ entities: [E]) -> Observable { return self.fixedTime(value, entities) } } diff --git a/Sources/Data/Entities/ResultEntity.swift b/Sources/Data/Entities/ResultEntity.swift new file mode 100644 index 0000000..df90793 --- /dev/null +++ b/Sources/Data/Entities/ResultEntity.swift @@ -0,0 +1,23 @@ +// +// ResultEntity.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/23. +// + +import Foundation + +public struct ResultEntity { + public var isReinforcement: Bool + public var entity: ResponseEntity + + public init(_ isReinforcement: Bool, _ entity: ResponseEntity) { + self.isReinforcement = isReinforcement + self.entity = entity + } + + public init(isReinforcement: Bool, entity: ResponseEntity) { + self.isReinforcement = isReinforcement + self.entity = entity + } +} diff --git a/Sources/Data/Parameters/FixedRatioParameter.swift b/Sources/Data/Parameters/FixedRatioParameter.swift new file mode 100644 index 0000000..529dd94 --- /dev/null +++ b/Sources/Data/Parameters/FixedRatioParameter.swift @@ -0,0 +1,17 @@ +// +// FixedRatioParameter.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/23. +// + +import Foundation + +public class FixedRatioParameter: ScheduleParameterable { + public var value: Int + public var values: [Int] = [] + + public init(_ value: Int) { + self.value = value + } +} diff --git a/Sources/Data/Recorders/ScheduleRecorder.swift b/Sources/Data/Recorders/ScheduleRecorder.swift new file mode 100644 index 0000000..7c9e008 --- /dev/null +++ b/Sources/Data/Recorders/ScheduleRecorder.swift @@ -0,0 +1,29 @@ +// +// ScheduleRecorder.swift +// OperantKit +// +// Created by Yuto Mizutani on 2018/11/23. +// + +import Foundation + +public class ScheduleRecorder: ExperimentRecordable, ScheduleRecordable { + public var lastReinforcementEntity: ResponseEntity = ResponseEntity() + public var extendEntity: ResponseEntity = ResponseEntity() + public var currentOrder: Int = 0 + public var currentValue: Int = 0 + + public init() {} + + public init( + lastReinforcementEntity: ResponseEntity = ResponseEntity(), + extendEntity: ResponseEntity = ResponseEntity(), + currentOrder: Int = 0, + currentValue: Int = 0 + ) { + self.lastReinforcementEntity = lastReinforcementEntity + self.extendEntity = extendEntity + self.currentOrder = currentOrder + self.currentValue = currentValue + } +} diff --git a/Sources/Data/Repositories/ScheduleRespositoryImpl.swift b/Sources/Data/Repositories/ScheduleRespositoryImpl.swift index 218285e..3739bfc 100644 --- a/Sources/Data/Repositories/ScheduleRespositoryImpl.swift +++ b/Sources/Data/Repositories/ScheduleRespositoryImpl.swift @@ -12,11 +12,16 @@ public class ScheduleRespositoryImpl: ScheduleRespository { private weak var recorder: (ScheduleRecordable & ExperimentRecordable)? public init(parameter: ScheduleParameterable, - recorder: (ScheduleRecordable & ExperimentRecordable)) { + recorder: ScheduleRecordable & ExperimentRecordable) { self.parameter = parameter self.recorder = recorder } + public init(dataStore: ScheduleParameterable & ScheduleRecordable & ExperimentRecordable) { + self.parameter = dataStore + self.recorder = dataStore + } + public func getValue() -> Single { return Single.create { [weak self] single in guard let recorder = self?.recorder else { @@ -30,20 +35,20 @@ public class ScheduleRespositoryImpl: ScheduleRespository { } } - public func nextValue(_ schedule: @escaping (ScheduleParameterable, ScheduleRecordable) -> ScheduleRecordable) -> Completable { - return Completable.create { [weak self] completable in + public func nextValue(_ schedule: @escaping (ScheduleParameterable, ScheduleRecordable) -> ScheduleRecordable) -> Single<()> { + return Single.create { [weak self] single in guard let parameter = self?.parameter, let recorder = self?.recorder else { - completable(.error(RxError.noElements)) + single(.error(RxError.noElements)) return Disposables.create() } let scheduleRecorder = schedule(parameter, recorder) recorder.currentOrder = scheduleRecorder.currentOrder recorder.currentValue = scheduleRecorder.currentValue - completable(.completed) + single(.success(())) return Disposables.create() } @@ -75,32 +80,31 @@ public class ScheduleRespositoryImpl: ScheduleRespository { } } - public func clearExtendProperty() -> Completable { - return Completable.create { [weak self] completable in + public func clearExtendProperty() -> Single<()> { + return Single.create { [weak self] single in guard let recorder = self?.recorder else { - completable(.error(RxError.noElements)) - return Disposables.create() + single(.error(RxError.noElements)) + return Disposables.create() } recorder.extendEntity = ResponseEntity() - completable(.completed) + single(.success(())) return Disposables.create() } } - public func updateLastReinforcementProperty(_ entity: ResponseEntity) -> Completable { - return Completable.create { [weak self] completable in + public func updateLastReinforcementProperty(_ entity: ResponseEntity) -> Single<()> { + return Single.create { [weak self] single in guard let recorder = self?.recorder else { - completable(.error(RxError.noElements)) + single(.error(RxError.noElements)) return Disposables.create() } recorder.lastReinforcementEntity = entity - completable(.completed) + single(.success(())) return Disposables.create() } } - } diff --git a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift index 00f8200..fb284f4 100644 --- a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift @@ -7,40 +7,55 @@ import RxSwift -public struct AlternativeScheduleUseCase { - private var _dataStore = FixedResponseDataStore(value: 0) - public var subSchedules: Matrix +public struct AlternativeScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? + public var subSchedules: [ScheduleUseCase] - public init(subSchedules: ScheduleUseCase...) { - self.subSchedules = Matrix(subSchedules)! + public var scheduleType: ScheduleType { + return ScheduleType( + rawValue: UInt64.max, + shortName: "Alt(\(subSchedules.map { $0.scheduleType.shortName }.joined(separator: ", ")))", + longName: "Alternative(\(subSchedules.map { $0.scheduleType.longName }.joined(separator: ", ")))" + ) } - public init(subSchedules: Matrix) { + public init(repository: ScheduleRespository, subSchedules: ScheduleUseCase...) { + self.repository = repository self.subSchedules = subSchedules } -} -extension AlternativeScheduleUseCase { - public var scheduleType: ScheduleType { - return ScheduleType( - rawValue: UInt64.max, - shortName: "Alt(\(subSchedules.elements.map { $0.scheduleType.shortName }.joined(separator: ", ")))", - longName: "Alternative(\(subSchedules.elements.map { $0.scheduleType.longName }.joined(separator: ", ")))" - ) + public init(repository: ScheduleRespository, subSchedules: [ScheduleUseCase]) { + self.repository = repository + self.subSchedules = subSchedules + } + + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let observables: [Observable] = subSchedules.map { $0.decision(observer, isUpdateIfReinforcement: false) } + + let result = observer.flatMap { observer in + return Observable.combineLatest(observables) + .map { ResultEntity(!$0.filter({ $0.isReinforcement }).isEmpty, observer) } + } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } -// public var dataStore: ExperimentDataStore { -// set { -// _dataStore.extendEntity = dataStore.extendEntity -// _dataStore.lastReinforcementEntity = dataStore.lastReinforcementEntity -// } -// get { -// return _dataStore -// } -// } - -// public func decision(_ observer: Observable, isAfterEffects: Bool = true) -> Observable { -//// let deicion = subSchedules.elements.map { $0.decision(observer, isAfterEffects: false) } -//// return !isAfterEffects ? decision : decision -// } + public func updateValue(_ observer: Observable) -> Observable { + let observables: [Observable] = subSchedules.map { $0.updateValue(observer) } + + return observer + .flatMap { observer -> Observable in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.clearExtendProperty().asObservable(), + repository.updateLastReinforcementProperty(observer.entity).asObservable(), + Observable.combineLatest(observables) + ) + .map { _ in observer } + } + } } diff --git a/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift b/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift index 86922cc..2c29f0d 100644 --- a/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift +++ b/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift @@ -19,14 +19,14 @@ public struct ConcurrentScheduleUseCase { } } -public extension ConcurrentScheduleUseCase { - func extendEntity(_ number: Int) -> ResponseEntity { - let number = dataStore.concurrentEntity.isShared ? 0 : number - return dataStore.concurrentEntity.subSchedules[number].extendEntity - } - - func decision(_ observer: Observable, number: Int) -> Observable { - let number = dataStore.concurrentEntity.isShared ? 0 : number - return dataStore.concurrentEntity.subSchedules[number].decision(observer) - } -} +//public extension ConcurrentScheduleUseCase { +// func extendEntity(_ number: Int) -> ResponseEntity { +// let number = dataStore.concurrentEntity.isShared ? 0 : number +// return dataStore.concurrentEntity.subSchedules[number].extendEntity +// } +// +// func decision(_ observer: Observable, number: Int) -> Observable { +// let number = dataStore.concurrentEntity.isShared ? 0 : number +// return dataStore.concurrentEntity.subSchedules[number].decision(observer) +// } +//} diff --git a/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift b/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift index 71e298f..e9c52a3 100644 --- a/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift +++ b/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift @@ -7,20 +7,18 @@ import RxSwift -public struct ExtinctionScheduleUseCase { - public init() {} -} +public struct ExtinctionScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? -extension ExtinctionScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .extinction } - public var extendEntity: ResponseEntity { - return ResponseEntity() + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { return observer.EXT() } } diff --git a/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift index ba72951..bb10428 100644 --- a/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift @@ -7,31 +7,35 @@ import RxSwift -public struct FixedIntervalScheduleUseCase { - public var dataStore: FixedResponseDataStore +public struct FixedIntervalScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, unit: TimeUnit) { - self.dataStore = FixedResponseDataStore(value: value, unit: unit) - } - - public init(dataStore: FixedResponseDataStore) { - self.dataStore = dataStore - } -} - -extension FixedIntervalScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .fixedInterval } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.FI(dataStore.fixedEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .FI(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift b/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift index 0cd34f4..7d91711 100644 --- a/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift @@ -7,31 +7,35 @@ import RxSwift -public struct FixedRatioScheduleUseCase { - public var dataStore: FixedResponseDataStore +public struct FixedRatioScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int) { - self.dataStore = FixedResponseDataStore(value: value) - } - - public init(dataStore: FixedResponseDataStore) { - self.dataStore = dataStore - } -} - -extension FixedRatioScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .fixedRatio } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.FR(dataStore.fixedEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .FR(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift b/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift index db108fc..5ec0650 100644 --- a/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift @@ -7,31 +7,35 @@ import RxSwift -public struct FixedTimeScheduleUseCase { - public var dataStore: FixedResponseDataStore +public struct FixedTimeScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, unit: TimeUnit) { - self.dataStore = FixedResponseDataStore(value: value, unit: unit) + public var scheduleType: ScheduleType { + return .randomRatio } - public init(dataStore: FixedResponseDataStore) { - self.dataStore = dataStore + public init(repository: ScheduleRespository) { + self.repository = repository } -} -extension FixedTimeScheduleUseCase: ScheduleUseCase { - public var scheduleType: ScheduleType { - return .fixedTime - } + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .FT(repository.getValue()) - public var extendEntity: ResponseEntity { - return dataStore.extendEntity - } + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } - public func decision(_ observer: Observable) -> Observable { - return observer.FT(dataStore.fixedEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift index 91a195b..9cf517b 100644 --- a/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift @@ -7,31 +7,35 @@ import RxSwift -public struct RandomIntervalScheduleUseCase { - public var dataStore: RandomResponseDataStore +public struct RandomIntervalScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, unit: TimeUnit) { - self.dataStore = RandomResponseDataStore(value: value, unit: unit) - } - - public init(dataStore: RandomResponseDataStore) { - self.dataStore = dataStore - } -} - -extension RandomIntervalScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .randomInterval } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.RI(dataStore.randomEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .RI(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift b/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift index bfcdd8d..845ab7f 100644 --- a/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift @@ -7,32 +7,35 @@ import RxSwift -public struct RandomRatioScheduleUseCase { - public var dataStore: RandomResponseDataStore +public struct RandomRatioScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int) { - self.dataStore = RandomResponseDataStore(value: value) - } - - public init(dataStore: RandomResponseDataStore) { - self.dataStore = dataStore - } -} - -extension RandomRatioScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .randomRatio } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.RR(dataStore.randomEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .nextRandom(dataStore.randomEntity, condition: { $0.isReinforcement }) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .RR(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift b/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift index 534b9b5..f3a3fdd 100644 --- a/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift @@ -7,31 +7,35 @@ import RxSwift -public struct RandomTimeScheduleUseCase { - public var dataStore: RandomResponseDataStore +public struct RandomTimeScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, unit: TimeUnit) { - self.dataStore = RandomResponseDataStore(value: value, unit: unit) - } - - public init(dataStore: RandomResponseDataStore) { - self.dataStore = dataStore - } -} - -extension RandomTimeScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .randomTime } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.RT(dataStore.randomEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .RT(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift index 485ae97..bec6473 100644 --- a/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift @@ -7,39 +7,35 @@ import RxSwift -public struct VariableIntervalScheduleUseCase { - public var dataStore: VariableResponseDataStore +public struct VariableIntervalScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, unit: TimeUnit, iterations: Int = 12) { - self.dataStore = VariableResponseDataStore(value: value, unit: unit, iterations: iterations) - } - - public init(value: Int, values: [Int], unit: TimeUnit) { - self.dataStore = VariableResponseDataStore(value: value, values: values, unit: unit) - } - - public init(value: Milliseconds, values: [Milliseconds]) { - self.dataStore = VariableResponseDataStore(value: value, values: values) - } - - public init(dataStore: VariableResponseDataStore) { - self.dataStore = dataStore - } -} - -extension VariableIntervalScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .variableInterval } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.VI(dataStore.variableEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .VI(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift b/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift index 7556cc0..23f0a1f 100644 --- a/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift @@ -7,36 +7,35 @@ import RxSwift -public struct VariableRatioScheduleUseCase { - public var dataStore: VariableResponseDataStore +public struct VariableRatioScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, iterations: Int) { - self.dataStore = VariableResponseDataStore(value: value, iterations: iterations) - } - - public init(value: Int, values: [Int]) { - self.dataStore = VariableResponseDataStore(value: value, values: values) - } - - public init(dataStore: VariableResponseDataStore) { - self.dataStore = dataStore - } -} - -extension VariableRatioScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { - return .variableRatio + return .fixedRatio } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.VR(dataStore.variableEntity.values[dataStore.variableEntity.order], - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .nextOrder(dataStore.variableEntity, condition: { $0.isReinforcement }) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .VR(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } diff --git a/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift b/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift index 7611fdc..004bc5e 100644 --- a/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift @@ -7,39 +7,35 @@ import RxSwift -public struct VariableTimeScheduleUseCase { - public var dataStore: VariableResponseDataStore +public struct VariableTimeScheduleUseCase: ScheduleUseCase { + public weak var repository: ScheduleRespository? - public init(value: Int, unit: TimeUnit, iterations: Int = 12) { - self.dataStore = VariableResponseDataStore(value: value, unit: unit, iterations: iterations) - } - - public init(value: Int, values: [Int], unit: TimeUnit) { - self.dataStore = VariableResponseDataStore(value: value, values: values, unit: unit) - } - - public init(value: Milliseconds, values: [Milliseconds]) { - self.dataStore = VariableResponseDataStore(value: value, values: values) - } - - public init(dataStore: VariableResponseDataStore) { - self.dataStore = dataStore - } -} - -extension VariableTimeScheduleUseCase: ScheduleUseCase { public var scheduleType: ScheduleType { return .variableTime } - public var extendEntity: ResponseEntity { - return dataStore.extendEntity + public init(repository: ScheduleRespository) { + self.repository = repository } - public func decision(_ observer: Observable) -> Observable { - return observer.VT(dataStore.variableEntity.nextValue, - with: dataStore.lastReinforcementEntity, dataStore.extendEntity) - .clearResponse(dataStore.extendEntity, condition: { $0.isReinforcement }) - .storeResponse(dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in + guard let repository = self.repository else { return Observable.error(RxError.noElements) } + return Observable.combineLatest( + repository.getExtendProperty().asObservable(), + repository.getLastReinforcementProperty().asObservable() + ) + .map { (observer - $0.0 - $0.1) } + } + .VT(repository.getValue()) + + let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + + return !isUpdateIfReinforcement ? result : result + .flatMap { observer -> Observable in + guard observer.isReinforcement else { return Observable.just(observer) } + return self.updateValue(result) + } } } From a020cdd4b267a027f5bf009209d01e455dc13ad8 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Fri, 23 Nov 2018 21:48:07 +0900 Subject: [PATCH 6/9] :+1: Remove weak #122 --- .../Protocols/ScheduleUseCase.swift | 21 ++++++++----------- .../UseCases/AlternativeScheduleUseCase.swift | 7 +++---- .../UseCases/ExtinctionScheduleUseCase.swift | 2 +- .../FixedIntervalScheduleUseCase.swift | 8 +++---- .../UseCases/FixedRatioScheduleUseCase.swift | 8 +++---- .../UseCases/FixedTimeScheduleUseCase.swift | 8 +++---- .../RandomIntervalScheduleUseCase.swift | 8 +++---- .../UseCases/RandomRatioScheduleUseCase.swift | 8 +++---- .../UseCases/RandomTimeScheduleUseCase.swift | 8 +++---- .../VariableIntervalScheduleUseCase.swift | 8 +++---- .../VariableRatioScheduleUseCase.swift | 8 +++---- .../VariableTimeScheduleUseCase.swift | 8 +++---- 12 files changed, 40 insertions(+), 62 deletions(-) diff --git a/Sources/Application/Protocols/ScheduleUseCase.swift b/Sources/Application/Protocols/ScheduleUseCase.swift index bda1e22..95559c8 100644 --- a/Sources/Application/Protocols/ScheduleUseCase.swift +++ b/Sources/Application/Protocols/ScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public protocol ScheduleUseCase { - var repository: ScheduleRespository? { get } + var repository: ScheduleRespository { get } var scheduleType: ScheduleType { get } /// Decision the reinforcement schedule @@ -22,11 +22,10 @@ public extension ScheduleUseCase { case let s where s.hasVariableSchedule(): return observer .flatMap { observer -> Observable in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.clearExtendProperty().asObservable(), - repository.updateLastReinforcementProperty(observer.entity).asObservable(), - repository.nextValue({ + self.repository.clearExtendProperty().asObservable(), + self.repository.updateLastReinforcementProperty(observer.entity).asObservable(), + self.repository.nextValue({ $1.currentOrder += 1 $1.currentValue = $0.values[$1.currentOrder % $0.values.count] return $1 @@ -37,11 +36,10 @@ public extension ScheduleUseCase { case let s where s.hasRandomSchedule(): return observer .flatMap { observer -> Observable in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.clearExtendProperty().asObservable(), - repository.updateLastReinforcementProperty(observer.entity).asObservable(), - repository.nextValue({ + self.repository.clearExtendProperty().asObservable(), + self.repository.updateLastReinforcementProperty(observer.entity).asObservable(), + self.repository.nextValue({ $1.currentValue = $0.value > 0 ? Int.random(in: 1...$0.value) : 1 return $1 }).asObservable() @@ -51,10 +49,9 @@ public extension ScheduleUseCase { default: return observer .flatMap { observer -> Observable in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.clearExtendProperty().asObservable(), - repository.updateLastReinforcementProperty(observer.entity).asObservable() + self.repository.clearExtendProperty().asObservable(), + self.repository.updateLastReinforcementProperty(observer.entity).asObservable() ) .map { _ in observer } } diff --git a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift index fb284f4..d923a29 100644 --- a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct AlternativeScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var subSchedules: [ScheduleUseCase] public var scheduleType: ScheduleType { @@ -49,10 +49,9 @@ public struct AlternativeScheduleUseCase: ScheduleUseCase { return observer .flatMap { observer -> Observable in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.clearExtendProperty().asObservable(), - repository.updateLastReinforcementProperty(observer.entity).asObservable(), + self.repository.clearExtendProperty().asObservable(), + self.repository.updateLastReinforcementProperty(observer.entity).asObservable(), Observable.combineLatest(observables) ) .map { _ in observer } diff --git a/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift b/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift index e9c52a3..770355d 100644 --- a/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift +++ b/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct ExtinctionScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .extinction diff --git a/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift index bb10428..c66429c 100644 --- a/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct FixedIntervalScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .fixedInterval @@ -19,12 +19,10 @@ public struct FixedIntervalScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift b/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift index 7d91711..9ca4fc6 100644 --- a/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct FixedRatioScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .fixedRatio @@ -19,12 +19,10 @@ public struct FixedRatioScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift b/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift index 5ec0650..7b4a609 100644 --- a/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct FixedTimeScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .randomRatio @@ -19,12 +19,10 @@ public struct FixedTimeScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift index 9cf517b..00bea4c 100644 --- a/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct RandomIntervalScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .randomInterval @@ -19,12 +19,10 @@ public struct RandomIntervalScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift b/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift index 845ab7f..dd6fc95 100644 --- a/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct RandomRatioScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .randomRatio @@ -19,12 +19,10 @@ public struct RandomRatioScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift b/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift index f3a3fdd..e6ad169 100644 --- a/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct RandomTimeScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .randomTime @@ -19,12 +19,10 @@ public struct RandomTimeScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift index bec6473..7bc3824 100644 --- a/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct VariableIntervalScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .variableInterval @@ -19,12 +19,10 @@ public struct VariableIntervalScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift b/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift index 23f0a1f..cdf4f41 100644 --- a/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct VariableRatioScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .fixedRatio @@ -19,12 +19,10 @@ public struct VariableRatioScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } diff --git a/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift b/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift index 004bc5e..279ea33 100644 --- a/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift @@ -8,7 +8,7 @@ import RxSwift public struct VariableTimeScheduleUseCase: ScheduleUseCase { - public weak var repository: ScheduleRespository? + public var repository: ScheduleRespository public var scheduleType: ScheduleType { return .variableTime @@ -19,12 +19,10 @@ public struct VariableTimeScheduleUseCase: ScheduleUseCase { } public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - guard let repository = self.repository else { return Observable.error(RxError.noElements) } let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - guard let repository = self.repository else { return Observable.error(RxError.noElements) } return Observable.combineLatest( - repository.getExtendProperty().asObservable(), - repository.getLastReinforcementProperty().asObservable() + self.repository.getExtendProperty().asObservable(), + self.repository.getLastReinforcementProperty().asObservable() ) .map { (observer - $0.0 - $0.1) } } From 6d4e460c57b31c7b24d2094437534e3172552dc2 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Fri, 23 Nov 2018 21:50:05 +0900 Subject: [PATCH 7/9] :+1: Fix comment #122 --- Sources/Common/Schedules/EXT.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Common/Schedules/EXT.swift b/Sources/Common/Schedules/EXT.swift index ac91e22..3f85e9f 100644 --- a/Sources/Common/Schedules/EXT.swift +++ b/Sources/Common/Schedules/EXT.swift @@ -9,12 +9,12 @@ import RxSwift extension Observable where E == ResponseEntity { - /// Fixed interval schedule + /// Extinction schedule public func EXT(_ value: Single) -> Observable { return extinction(value) } - /// FI logic + /// EXT logic func extinction(_ value: Single) -> Observable { return map { _ in false } } From 18a8e2f0e837bcf35b32c25f1825d7494582e198 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Sat, 24 Nov 2018 04:55:32 +0900 Subject: [PATCH 8/9] :tada: Update UseCase and fix test #122 --- .../sandbox/Experiments/ExperimentFR.swift | 11 +- OperantKit.xcodeproj/project.pbxproj | 10 - .../ConcurrentScheduleUseCase+Shared.swift | 14 - .../Extensions/ScheduleUseCase+.swift | 241 ++++++++++++++---- .../Protocols/ScheduleUseCase.swift | 11 +- .../DataStores/ScheduleDataStoreImpl.swift | 7 + .../ScheduleRespositoryImpl.swift | 21 +- .../UseCases/AlternativeScheduleUseCase.swift | 6 +- .../UseCases/ConcurrentScheduleUseCase.swift | 57 +++-- .../UseCases/ExtinctionScheduleUseCase.swift | 2 +- .../FixedIntervalScheduleUseCase.swift | 16 +- .../UseCases/FixedRatioScheduleUseCase.swift | 16 +- .../UseCases/FixedTimeScheduleUseCase.swift | 16 +- .../RandomIntervalScheduleUseCase.swift | 16 +- .../UseCases/RandomRatioScheduleUseCase.swift | 16 +- .../UseCases/RandomTimeScheduleUseCase.swift | 16 +- .../VariableIntervalScheduleUseCase.swift | 16 +- .../VariableRatioScheduleUseCase.swift | 16 +- .../VariableTimeScheduleUseCase.swift | 16 +- .../VariableIntervalScheduleTests.swift | 2 +- .../VariableRatioScheduleTests.swift | 2 +- .../VariableTimeScheduleTests.swift | 2 +- 22 files changed, 348 insertions(+), 182 deletions(-) delete mode 100644 Sources/Application/Extensions/ConcurrentScheduleUseCase+Shared.swift diff --git a/Examples/CLI/sandbox/Sources/sandbox/Experiments/ExperimentFR.swift b/Examples/CLI/sandbox/Sources/sandbox/Experiments/ExperimentFR.swift index 573e84a..3cc0e70 100644 --- a/Examples/CLI/sandbox/Sources/sandbox/Experiments/ExperimentFR.swift +++ b/Examples/CLI/sandbox/Sources/sandbox/Experiments/ExperimentFR.swift @@ -18,16 +18,7 @@ struct ExperimentFR { let finishTimerAction = PublishSubject() let disposeBag = DisposeBag() - let numOfResponses = responseAction - .scan(0) { n, _ in n + 1 } - .asObservable() - - let milliseconds = responseAction - .asObservable() - .flatMap { _ in timer.elapsed() } - - let response = Observable.zip(numOfResponses, milliseconds) - .map { ResponseEntity(numOfResponses: $0.0, milliseconds: $0.1) } + let response = responseAction.response(timer) .do(onNext: { print("Response: \($0.numOfResponses), \($0.milliseconds)ms") }) .share(replay: 1) diff --git a/OperantKit.xcodeproj/project.pbxproj b/OperantKit.xcodeproj/project.pbxproj index ae7d070..28cabd1 100644 --- a/OperantKit.xcodeproj/project.pbxproj +++ b/OperantKit.xcodeproj/project.pbxproj @@ -192,8 +192,6 @@ 999C7D1C21951CDC0044C47E /* Observable+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9E21951CDB0044C47E /* Observable+.swift */; }; 999C7D1E21951CDC0044C47E /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */; }; 999C7D1F21951CDC0044C47E /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */; }; - 999C7D2121951CDC0044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; - 999C7D2221951CDC0044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; 999C7D2421951CDC0044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; 999C7D2521951CDC0044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; 999C7D2721951CDC0044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; @@ -239,7 +237,6 @@ 999C7D96219533150044C47E /* TimeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9C21951CDB0044C47E /* TimeUnit.swift */; }; 999C7D97219533150044C47E /* Observable+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9E21951CDB0044C47E /* Observable+.swift */; }; 999C7D98219533150044C47E /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */; }; - 999C7D99219533150044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; 999C7D9A219533150044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; 999C7D9B219533150044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; 999C7D9C219533150044C47E /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */; }; @@ -292,7 +289,6 @@ 999C7DEA219542610044C47E /* TimeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9C21951CDB0044C47E /* TimeUnit.swift */; }; 999C7DEB219542610044C47E /* Observable+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9E21951CDB0044C47E /* Observable+.swift */; }; 999C7DEC219542610044C47E /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */; }; - 999C7DED219542610044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */; }; 999C7DEE219542610044C47E /* ObservableType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA121951CDB0044C47E /* ObservableType+.swift */; }; 999C7DEF219542610044C47E /* ResultEntity+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */; }; 999C7DF0219542610044C47E /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */; }; @@ -552,7 +548,6 @@ 999C7C9C21951CDB0044C47E /* TimeUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeUnit.swift; sourceTree = ""; }; 999C7C9E21951CDB0044C47E /* Observable+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+.swift"; sourceTree = ""; }; 999C7C9F21951CDB0044C47E /* UIApplication+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Rx.swift"; sourceTree = ""; }; - 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConcurrentScheduleUseCase+Shared.swift"; sourceTree = ""; }; 999C7CA121951CDB0044C47E /* ObservableType+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ObservableType+.swift"; sourceTree = ""; }; 999C7CA221951CDB0044C47E /* ResultEntity+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ResultEntity+Rx.swift"; sourceTree = ""; }; 999C7CA321951CDB0044C47E /* UIViewController+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Rx.swift"; sourceTree = ""; }; @@ -979,7 +974,6 @@ children = ( 99AE65BD21A2D3450090B308 /* Primitive */, 99AE65BE21A2D3520090B308 /* Rx */, - 999C7CA021951CDB0044C47E /* ConcurrentScheduleUseCase+Shared.swift */, 99C7517F21A06ED000DABE14 /* ScheduleUseCase+.swift */, ); path = Extensions; @@ -1603,7 +1597,6 @@ 999C7CF721951CDC0044C47E /* RandomResponseDataStore.swift in Sources */, 999C7D1B21951CDC0044C47E /* Observable+.swift in Sources */, 999C7CD021951CDB0044C47E /* FleshlerHoffman.swift in Sources */, - 999C7D2121951CDC0044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7CB221951CDB0044C47E /* FR.swift in Sources */, 999C7D2D21951CDC0044C47E /* ScheduleParameter.swift in Sources */, 99C74F0D219A77B300DABE14 /* VT.swift in Sources */, @@ -1725,7 +1718,6 @@ 9965656321A67825004C76F0 /* FixedParameter.swift in Sources */, 999C7D1C21951CDC0044C47E /* Observable+.swift in Sources */, 999C7CD121951CDB0044C47E /* FleshlerHoffman.swift in Sources */, - 999C7D2221951CDC0044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7CB321951CDB0044C47E /* FR.swift in Sources */, 9965652221A65966004C76F0 /* DiscreteTrialParameter.swift in Sources */, 9965657721A686C2004C76F0 /* ScheduleRespositoryImpl.swift in Sources */, @@ -1772,7 +1764,6 @@ 999C7D96219533150044C47E /* TimeUnit.swift in Sources */, 999C7D97219533150044C47E /* Observable+.swift in Sources */, 999C7D98219533150044C47E /* UIApplication+Rx.swift in Sources */, - 999C7D99219533150044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7D9A219533150044C47E /* ObservableType+.swift in Sources */, 99C7518921A077AB00DABE14 /* Responsible.swift in Sources */, 999C7D9B219533150044C47E /* ResultEntity+Rx.swift in Sources */, @@ -1894,7 +1885,6 @@ 999C7DEA219542610044C47E /* TimeUnit.swift in Sources */, 999C7DEB219542610044C47E /* Observable+.swift in Sources */, 999C7DEC219542610044C47E /* UIApplication+Rx.swift in Sources */, - 999C7DED219542610044C47E /* ConcurrentScheduleUseCase+Shared.swift in Sources */, 999C7DEE219542610044C47E /* ObservableType+.swift in Sources */, 99C7518A21A077AB00DABE14 /* Responsible.swift in Sources */, 999C7DEF219542610044C47E /* ResultEntity+Rx.swift in Sources */, diff --git a/Sources/Application/Extensions/ConcurrentScheduleUseCase+Shared.swift b/Sources/Application/Extensions/ConcurrentScheduleUseCase+Shared.swift deleted file mode 100644 index 052e6f9..0000000 --- a/Sources/Application/Extensions/ConcurrentScheduleUseCase+Shared.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// ConcurrentScheduleUseCase+Shared.swift -// OperantKit -// -// Created by Yuto Mizutani on 2018/11/08. -// - -import Foundation - -public extension ConcurrentScheduleUseCase { - init(_ sharedSchedule: Shared) { - self.init(subSchedules: [sharedSchedule.element], isShared: true) - } -} diff --git a/Sources/Application/Extensions/ScheduleUseCase+.swift b/Sources/Application/Extensions/ScheduleUseCase+.swift index cd7a1cb..d5504d5 100644 --- a/Sources/Application/Extensions/ScheduleUseCase+.swift +++ b/Sources/Application/Extensions/ScheduleUseCase+.swift @@ -7,60 +7,189 @@ import Foundation -// TODO: Add empty DataStore and Repository +public func EXT(repository: ScheduleRespository = ScheduleRespositoryImpl(value: 0, values: [])) -> ExtinctionScheduleUseCase { + return ExtinctionScheduleUseCase(repository: repository) +} -//public func EXT() -> ExtinctionScheduleUseCase { -// return ExtinctionScheduleUseCase() -//} -// -//public func CRF() -> FixedRatioScheduleUseCase { -// return FixedRatioScheduleUseCase(value: 1) -//} -// -//public func FR(_ value: Int) -> FixedRatioScheduleUseCase { -// return FixedRatioScheduleUseCase(value: value) -//} -// -//public func VR(_ value: Int, iterations: Int = 12) -> VariableRatioScheduleUseCase { -// return VariableRatioScheduleUseCase(value: value, iterations: iterations) -//} -// -//public func VR(_ value: Int, values: [Int]) -> VariableRatioScheduleUseCase { -// return VariableRatioScheduleUseCase(value: value, values: values) -//} -// -//public func RR(_ value: Int) -> RandomRatioScheduleUseCase { -// return RandomRatioScheduleUseCase(value: value) -//} -// -//public func FI(_ value: Int, unit: TimeUnit = .seconds) -> FixedIntervalScheduleUseCase { -// return FixedIntervalScheduleUseCase(value: value, unit: unit) -//} -// -//public func VI(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableIntervalScheduleUseCase { -// return VariableIntervalScheduleUseCase(value: value, unit: unit, iterations: iterations) -//} -// -//public func RI(_ value: Int, unit: TimeUnit = .seconds) -> RandomIntervalScheduleUseCase { -// return RandomIntervalScheduleUseCase(value: value, unit: unit) -//} -// -//public func FT(_ value: Int, unit: TimeUnit = .seconds) -> FixedTimeScheduleUseCase { -// return FixedTimeScheduleUseCase(value: value, unit: unit) -//} -// -//public func VT(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableTimeScheduleUseCase { -// return VariableTimeScheduleUseCase(value: value, unit: unit, iterations: iterations) -//} -// -//public func RT(_ value: Int, unit: TimeUnit = .seconds) -> RandomTimeScheduleUseCase { -// return RandomTimeScheduleUseCase(value: value, unit: unit) -//} -// -//public func Conc(_ subSchedules: ScheduleUseCase...) -> ConcurrentScheduleUseCase { -// return ConcurrentScheduleUseCase(subSchedules: subSchedules, isShared: false) -//} -// -//public func Conc(_ sharedSchedule: Shared) -> ConcurrentScheduleUseCase { -// return ConcurrentScheduleUseCase(sharedSchedule) -//} +public func CRF(repository: ScheduleRespository = ScheduleRespositoryImpl(value: 1, values: [])) -> FixedRatioScheduleUseCase { + return FixedRatioScheduleUseCase(repository: repository) +} + +public func FR(repository: ScheduleRespository) -> FixedRatioScheduleUseCase { + return FixedRatioScheduleUseCase(repository: repository) +} + +public func FR(_ value: Int) -> FixedRatioScheduleUseCase { + return FixedRatioScheduleUseCase( + repository: ScheduleRespositoryImpl(value: value, values: []) + ) +} + +public func VR(repository: ScheduleRespository) -> VariableRatioScheduleUseCase { + return VariableRatioScheduleUseCase(repository: repository) +} + +public func VR(_ value: Int, iterations: Int = 12) -> VariableRatioScheduleUseCase { + return VariableRatioScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: FleshlerHoffman().generatedRatio( + value: value, + iterations: iterations + ) + ) + ) +} + +public func VR(_ value: Int, values: [Int]) -> VariableRatioScheduleUseCase { + return VariableRatioScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: values + ) + ) +} + +public func RR(repository: ScheduleRespository) -> RandomRatioScheduleUseCase { + return RandomRatioScheduleUseCase(repository: repository) +} + +public func RR(_ value: Int) -> RandomRatioScheduleUseCase { + return RandomRatioScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: [], + initValue: value > 0 ? Int.random(in: 1...value) : 1 + ) + ) +} + +public func FI(repository: ScheduleRespository) -> FixedIntervalScheduleUseCase { + return FixedIntervalScheduleUseCase(repository: repository) +} + +public func FI(_ value: Int, unit: TimeUnit = .seconds) -> FixedIntervalScheduleUseCase { + return FixedIntervalScheduleUseCase( + repository: ScheduleRespositoryImpl(value: unit.milliseconds(value), values: []) + ) +} + +public func VI(repository: ScheduleRespository) -> VariableIntervalScheduleUseCase { + return VariableIntervalScheduleUseCase(repository: repository) +} + +public func VI(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableIntervalScheduleUseCase { + let value = unit.milliseconds(value) + return VariableIntervalScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: FleshlerHoffman().generatedInterval( + value: value, + iterations: iterations + ) + ) + ) +} + +public func VI(_ value: Int, values: [Int]) -> VariableIntervalScheduleUseCase { + return VariableIntervalScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: values + ) + ) +} + +public func RI(repository: ScheduleRespository) -> RandomIntervalScheduleUseCase { + return RandomIntervalScheduleUseCase(repository: repository) +} + +public func RI(_ value: Int, unit: TimeUnit = .seconds) -> RandomIntervalScheduleUseCase { + let value = unit.milliseconds(value) + return RandomIntervalScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: [], + initValue: value > 0 ? Int.random(in: 1...value) : 1 + ) + ) +} + +public func FT(repository: ScheduleRespository) -> FixedTimeScheduleUseCase { + return FixedTimeScheduleUseCase(repository: repository) +} + +public func FT(_ value: Int, unit: TimeUnit = .seconds) -> FixedTimeScheduleUseCase { + return FixedTimeScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: unit.milliseconds(value), + values: [] + ) + ) +} + +public func VT(repository: ScheduleRespository) -> VariableTimeScheduleUseCase { + return VariableTimeScheduleUseCase(repository: repository) +} + +public func VT(_ value: Int, unit: TimeUnit = .seconds, iterations: Int = 12) -> VariableTimeScheduleUseCase { + let value = unit.milliseconds(value) + return VariableTimeScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: FleshlerHoffman().generatedInterval( + value: value, + iterations: iterations + ) + ) + ) +} + +public func VT(_ value: Int, values: [Int]) -> VariableTimeScheduleUseCase { + return VariableTimeScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: values + ) + ) +} + +public func RT(repository: ScheduleRespository) -> RandomTimeScheduleUseCase { + return RandomTimeScheduleUseCase(repository: repository) +} + +public func RT(_ value: Int, unit: TimeUnit = .seconds) -> RandomTimeScheduleUseCase { + let value = unit.milliseconds(value) + return RandomTimeScheduleUseCase( + repository: ScheduleRespositoryImpl( + value: value, + values: [], + initValue: value > 0 ? Int.random(in: 1...value) : 1 + ) + ) +} + +public func Alt(repository: ScheduleRespository = ScheduleRespositoryImpl(), subSchedules: ScheduleUseCase...) -> AlternativeScheduleUseCase { + return AlternativeScheduleUseCase(repository: repository, subSchedules: subSchedules) +} + +public func Alt(repository: ScheduleRespository = ScheduleRespositoryImpl(), subSchedules: [ScheduleUseCase]) -> AlternativeScheduleUseCase { + return AlternativeScheduleUseCase(repository: repository, subSchedules: subSchedules) +} + +public func Conc(repository: ScheduleRespository) -> ConcurrentScheduleUseCase { + return ConcurrentScheduleUseCase(repository: repository) +} + +public func Conc(repository: ScheduleRespository = ScheduleRespositoryImpl(), subSchedules: ScheduleUseCase...) -> ConcurrentScheduleUseCase { + return ConcurrentScheduleUseCase( + repository: repository, + subSchedules: subSchedules + ) +} + +public func Conc(repository: ScheduleRespository = ScheduleRespositoryImpl(), sharedSchedule: Shared) -> ConcurrentScheduleUseCase { + return ConcurrentScheduleUseCase( + repository: repository, sharedSchedule: sharedSchedule + ) +} diff --git a/Sources/Application/Protocols/ScheduleUseCase.swift b/Sources/Application/Protocols/ScheduleUseCase.swift index 95559c8..4ddb606 100644 --- a/Sources/Application/Protocols/ScheduleUseCase.swift +++ b/Sources/Application/Protocols/ScheduleUseCase.swift @@ -12,17 +12,22 @@ public protocol ScheduleUseCase { var scheduleType: ScheduleType { get } /// Decision the reinforcement schedule + func decision(_ observer: Observable) -> Observable func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable func updateValue(_ observer: Observable) -> Observable } public extension ScheduleUseCase { + func decision(_ observer: Observable) -> Observable { + return decision(observer, isUpdateIfReinforcement: true) + } + func updateValue(_ observer: Observable) -> Observable { switch scheduleType { case let s where s.hasVariableSchedule(): return observer .flatMap { observer -> Observable in - return Observable.combineLatest( + return Observable.zip( self.repository.clearExtendProperty().asObservable(), self.repository.updateLastReinforcementProperty(observer.entity).asObservable(), self.repository.nextValue({ @@ -36,7 +41,7 @@ public extension ScheduleUseCase { case let s where s.hasRandomSchedule(): return observer .flatMap { observer -> Observable in - return Observable.combineLatest( + return Observable.zip( self.repository.clearExtendProperty().asObservable(), self.repository.updateLastReinforcementProperty(observer.entity).asObservable(), self.repository.nextValue({ @@ -49,7 +54,7 @@ public extension ScheduleUseCase { default: return observer .flatMap { observer -> Observable in - return Observable.combineLatest( + return Observable.zip( self.repository.clearExtendProperty().asObservable(), self.repository.updateLastReinforcementProperty(observer.entity).asObservable() ) diff --git a/Sources/Data/DataStores/ScheduleDataStoreImpl.swift b/Sources/Data/DataStores/ScheduleDataStoreImpl.swift index a225e47..5986520 100644 --- a/Sources/Data/DataStores/ScheduleDataStoreImpl.swift +++ b/Sources/Data/DataStores/ScheduleDataStoreImpl.swift @@ -18,5 +18,12 @@ public class ScheduleDataStoreImpl: ScheduleParameterable, ScheduleRecordable, E public init(value: Int, values: [Int] = []) { self.value = value self.values = values + self.currentValue = !values.isEmpty ? values[currentOrder] : value + } + + public init(value: Int, values: [Int] = [], initValue: Int) { + self.value = value + self.values = values + self.currentValue = initValue } } diff --git a/Sources/Data/Repositories/ScheduleRespositoryImpl.swift b/Sources/Data/Repositories/ScheduleRespositoryImpl.swift index 3739bfc..994d7d5 100644 --- a/Sources/Data/Repositories/ScheduleRespositoryImpl.swift +++ b/Sources/Data/Repositories/ScheduleRespositoryImpl.swift @@ -8,8 +8,8 @@ import RxSwift public class ScheduleRespositoryImpl: ScheduleRespository { - private weak var parameter: ScheduleParameterable? - private weak var recorder: (ScheduleRecordable & ExperimentRecordable)? + private var parameter: ScheduleParameterable + private var recorder: (ScheduleRecordable & ExperimentRecordable) public init(parameter: ScheduleParameterable, recorder: ScheduleRecordable & ExperimentRecordable) { @@ -108,3 +108,20 @@ public class ScheduleRespositoryImpl: ScheduleRespository { } } } + +public extension ScheduleRespositoryImpl { + convenience init() { + let dataStore = ScheduleDataStoreImpl(value: 0, values: []) + self.init(dataStore: dataStore) + } + + convenience init(value: Int, values: [Int]) { + let dataStore = ScheduleDataStoreImpl(value: value, values: values) + self.init(dataStore: dataStore) + } + + convenience init(value: Int, values: [Int], initValue: Int) { + let dataStore = ScheduleDataStoreImpl(value: value, values: values, initValue: initValue) + self.init(dataStore: dataStore) + } +} diff --git a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift index d923a29..748142d 100644 --- a/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/AlternativeScheduleUseCase.swift @@ -33,7 +33,7 @@ public struct AlternativeScheduleUseCase: ScheduleUseCase { let observables: [Observable] = subSchedules.map { $0.decision(observer, isUpdateIfReinforcement: false) } let result = observer.flatMap { observer in - return Observable.combineLatest(observables) + return Observable.zip(observables) .map { ResultEntity(!$0.filter({ $0.isReinforcement }).isEmpty, observer) } } @@ -49,10 +49,10 @@ public struct AlternativeScheduleUseCase: ScheduleUseCase { return observer .flatMap { observer -> Observable in - return Observable.combineLatest( + return Observable.zip( self.repository.clearExtendProperty().asObservable(), self.repository.updateLastReinforcementProperty(observer.entity).asObservable(), - Observable.combineLatest(observables) + Observable.zip(observables) ) .map { _ in observer } } diff --git a/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift b/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift index 2c29f0d..16d83a9 100644 --- a/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift +++ b/Sources/Domain/UseCases/ConcurrentScheduleUseCase.swift @@ -7,26 +7,49 @@ import RxSwift -public struct ConcurrentScheduleUseCase { - public var dataStore: ConcurrentResponseDataStore +public struct ConcurrentScheduleUseCase: ScheduleUseCase { + public var repository: ScheduleRespository + public var subSchedules: [ScheduleUseCase] + public var isShared: Bool + public var scheduleType: ScheduleType = ScheduleType(rawValue: UInt64.max) - public init(subSchedules: [ScheduleUseCase], isShared: Bool = false) { - self.dataStore = ConcurrentResponseDataStore(subSchedules: subSchedules, isShared: isShared) + public init(repository: ScheduleRespository, subSchedules: ScheduleUseCase..., isShared: Bool = false) { + self.repository = repository + self.subSchedules = subSchedules + self.isShared = isShared } - public init(dataStore: ConcurrentResponseDataStore) { - self.dataStore = dataStore + public init(repository: ScheduleRespository, subSchedules: [ScheduleUseCase]) { + self.repository = repository + self.subSchedules = subSchedules + self.isShared = false + } + + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + guard !subSchedules.isEmpty else { return Observable.error(RxError.noElements) } + return subSchedules[0].decision(observer, isUpdateIfReinforcement: isUpdateIfReinforcement) + } + + public func updateValue(_ observer: Observable) -> Observable { + guard !subSchedules.isEmpty else { return Observable.error(RxError.noElements) } + return subSchedules[0].updateValue(observer) + } + + public func decision(_ observer: Observable, order: Int, isUpdateIfReinforcement: Bool = true) -> Observable { + guard isShared || subSchedules.count > order else { return Observable.error(RxError.noElements) } + return subSchedules[isShared ? 0 : order].decision(observer, isUpdateIfReinforcement: isUpdateIfReinforcement) + } + + public func updateValue(_ observer: Observable, order: Int) -> Observable { + guard isShared || subSchedules.count > order else { return Observable.error(RxError.noElements) } + return subSchedules[isShared ? 0 : order].updateValue(observer) } } -//public extension ConcurrentScheduleUseCase { -// func extendEntity(_ number: Int) -> ResponseEntity { -// let number = dataStore.concurrentEntity.isShared ? 0 : number -// return dataStore.concurrentEntity.subSchedules[number].extendEntity -// } -// -// func decision(_ observer: Observable, number: Int) -> Observable { -// let number = dataStore.concurrentEntity.isShared ? 0 : number -// return dataStore.concurrentEntity.subSchedules[number].decision(observer) -// } -//} +public extension ConcurrentScheduleUseCase { + init(repository: ScheduleRespository, sharedSchedule: Shared) { + self.repository = repository + self.subSchedules = [sharedSchedule.element] + self.isShared = true + } +} diff --git a/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift b/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift index 770355d..42f5ced 100644 --- a/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift +++ b/Sources/Domain/UseCases/ExtinctionScheduleUseCase.swift @@ -18,7 +18,7 @@ public struct ExtinctionScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { return observer.EXT() } } diff --git a/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift index c66429c..d2e28bc 100644 --- a/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedIntervalScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct FixedIntervalScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct FixedIntervalScheduleUseCase: ScheduleUseCase { } .FI(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift b/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift index 9ca4fc6..0a0babe 100644 --- a/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedRatioScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct FixedRatioScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct FixedRatioScheduleUseCase: ScheduleUseCase { } .FR(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift b/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift index 7b4a609..b520a69 100644 --- a/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/FixedTimeScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct FixedTimeScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct FixedTimeScheduleUseCase: ScheduleUseCase { } .FT(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift index 00bea4c..f04b500 100644 --- a/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomIntervalScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct RandomIntervalScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct RandomIntervalScheduleUseCase: ScheduleUseCase { } .RI(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift b/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift index dd6fc95..f7911bf 100644 --- a/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomRatioScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct RandomRatioScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct RandomRatioScheduleUseCase: ScheduleUseCase { } .RR(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift b/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift index e6ad169..59a1b83 100644 --- a/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/RandomTimeScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct RandomTimeScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct RandomTimeScheduleUseCase: ScheduleUseCase { } .RT(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift b/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift index 7bc3824..fe3c76f 100644 --- a/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableIntervalScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct VariableIntervalScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct VariableIntervalScheduleUseCase: ScheduleUseCase { } .VI(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift b/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift index cdf4f41..f10d950 100644 --- a/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableRatioScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct VariableRatioScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct VariableRatioScheduleUseCase: ScheduleUseCase { } .VR(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift b/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift index 279ea33..91b1932 100644 --- a/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift +++ b/Sources/Domain/UseCases/VariableTimeScheduleUseCase.swift @@ -18,9 +18,10 @@ public struct VariableTimeScheduleUseCase: ScheduleUseCase { self.repository = repository } - public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool = true) -> Observable { - let bool = observer.flatMap { observer -> Observable<(ResponseEntity)> in - return Observable.combineLatest( + public func decision(_ observer: Observable, isUpdateIfReinforcement: Bool) -> Observable { + let sharedObserver = observer.share(replay: 1) + let bool = sharedObserver.flatMap { observer -> Observable<(ResponseEntity)> in + return Observable.zip( self.repository.getExtendProperty().asObservable(), self.repository.getLastReinforcementProperty().asObservable() ) @@ -28,12 +29,13 @@ public struct VariableTimeScheduleUseCase: ScheduleUseCase { } .VT(repository.getValue()) - let result = Observable.zip(bool, observer).map { ResultEntity($0.0, $0.1) } + let result = Observable.zip(bool, sharedObserver).map { ResultEntity($0.0, $0.1) } return !isUpdateIfReinforcement ? result : result - .flatMap { observer -> Observable in - guard observer.isReinforcement else { return Observable.just(observer) } - return self.updateValue(result) + .flatMap { + $0.isReinforcement + ? self.updateValue(Observable.just($0)) + : Observable.just($0) } } } diff --git a/Tests/ScheduleTests/VariableIntervalScheduleTests.swift b/Tests/ScheduleTests/VariableIntervalScheduleTests.swift index e36f5c8..1410f48 100644 --- a/Tests/ScheduleTests/VariableIntervalScheduleTests.swift +++ b/Tests/ScheduleTests/VariableIntervalScheduleTests.swift @@ -54,7 +54,7 @@ final class VariablIntervaleScheduleTests: XCTestCase { let disposeBag = DisposeBag() let values: [Milliseconds] = [5, 5, 5] - let schedule: ScheduleUseCase = VariableIntervalScheduleUseCase(value: 5, values: values) + let schedule: ScheduleUseCase = VI(5, values: values) let testObservable = scheduler.createHotObservable([ next(100, ResponseEntity(numOfResponses: 0, milliseconds: 5)), diff --git a/Tests/ScheduleTests/VariableRatioScheduleTests.swift b/Tests/ScheduleTests/VariableRatioScheduleTests.swift index d7415c6..73b2137 100644 --- a/Tests/ScheduleTests/VariableRatioScheduleTests.swift +++ b/Tests/ScheduleTests/VariableRatioScheduleTests.swift @@ -54,7 +54,7 @@ final class VariableRatioScheduleTests: XCTestCase { let disposeBag = DisposeBag() let values: [Int] = [5, 5, 5] - let schedule: ScheduleUseCase = VariableRatioScheduleUseCase(value: 5, values: values) + let schedule: ScheduleUseCase = VR(5, values: values) let testObservable = scheduler.createHotObservable([ next(100, ResponseEntity(numOfResponses: 5, milliseconds: 0)), diff --git a/Tests/ScheduleTests/VariableTimeScheduleTests.swift b/Tests/ScheduleTests/VariableTimeScheduleTests.swift index 94f08c0..6e0f63f 100644 --- a/Tests/ScheduleTests/VariableTimeScheduleTests.swift +++ b/Tests/ScheduleTests/VariableTimeScheduleTests.swift @@ -54,7 +54,7 @@ final class VariableTimeScheduleTests: XCTestCase { let disposeBag = DisposeBag() let values: [Milliseconds] = [5, 5, 5] - let schedule: ScheduleUseCase = VariableTimeScheduleUseCase(value: 5, values: values) + let schedule: ScheduleUseCase = VT(5, values: values) let testObservable = scheduler.createHotObservable([ next(100, ResponseEntity(numOfResponses: 0, milliseconds: 5)), From bcd3f36351accc686647cd889af9ecb72a1ef715 Mon Sep 17 00:00:00 2001 From: YutoMizutani Date: Sat, 24 Nov 2018 04:56:43 +0900 Subject: [PATCH 9/9] :fire: Remove playground #122 --- OperantKit.xcodeproj/project.pbxproj | 2 - .../Contents.swift | 147 ------------------ .../contents.xcplayground | 4 - 3 files changed, 153 deletions(-) delete mode 100644 OperantKitPlayground.playground/Contents.swift delete mode 100644 OperantKitPlayground.playground/contents.xcplayground diff --git a/OperantKit.xcodeproj/project.pbxproj b/OperantKit.xcodeproj/project.pbxproj index 28cabd1..a02cdaf 100644 --- a/OperantKit.xcodeproj/project.pbxproj +++ b/OperantKit.xcodeproj/project.pbxproj @@ -488,7 +488,6 @@ 9965652621A6597C004C76F0 /* DiscreteTrialRecordable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialRecordable.swift; sourceTree = ""; }; 9965653C21A66A72004C76F0 /* DiscreteTrialRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialRepository.swift; sourceTree = ""; }; 9965654121A66BA9004C76F0 /* DiscreteTrialUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialUseCase.swift; sourceTree = ""; }; - 9965654821A66CDA004C76F0 /* OperantKitPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = OperantKitPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 9965654921A66D81004C76F0 /* DiscreteTrialRepositoryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialRepositoryImpl.swift; sourceTree = ""; }; 9965654E21A66DB8004C76F0 /* DiscreteTrialUseCaseImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialUseCaseImpl.swift; sourceTree = ""; }; 9965655321A66F41004C76F0 /* DiscreteTrialDataStoreImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteTrialDataStoreImpl.swift; sourceTree = ""; }; @@ -1169,7 +1168,6 @@ OBJ_5 = { isa = PBXGroup; children = ( - 9965654821A66CDA004C76F0 /* OperantKitPlayground.playground */, OBJ_6 /* Package.swift */, 994FFF5B212C27B3000F4702 /* Supporting Files */, OBJ_7 /* Sources */, diff --git a/OperantKitPlayground.playground/Contents.swift b/OperantKitPlayground.playground/Contents.swift deleted file mode 100644 index 534e21f..0000000 --- a/OperantKitPlayground.playground/Contents.swift +++ /dev/null @@ -1,147 +0,0 @@ -import OperantKit -import RxCocoa -import RxSwift - -func builder() { - let useCase: FixedRatioScheduleUseCase = FixedRatioScheduleUseCase( - repository: ScheduleRespositoryImpl( - dataStore: ScheduleDataStoreImpl(value: 5) - ) - ) -} - -//func builder() { -// let useCase: DiscreteTrialUseCase = DiscreteTrialUseCaseImpl( -// repository: DiscreteTrialRepositoryImpl( -// dataStore: DiscreteTrialDataStoreImpl( -// maxTrials: 2, -// parameters: [], -// records: [] -// ) -// ) -// ) -//} -// -//let numberOfPairings: Int = 80 -//let whiteKeyLightDuration: Seconds = 8 -//let trayOperatingDuration: Milliseconds = 4000 -//let interTrialInterval: [Seconds] = [Seconds](5...10) // (30...90) -// .filter({ $0 % 5 == 0 }) -// .map { TimeUnit.seconds.milliseconds($0) } -// .shuffled() -// -//var nextInterval: Milliseconds = 0 -//var currentOrder: Int = 0 -//func updateInterval() { -// nextInterval = interTrialInterval[currentOrder % interTrialInterval.count] -//} -// -//let timer = WhileLoopTimerUseCase(priority: .high) -//let fixedTimeSchedule = FT(whiteKeyLightDuration) -//let continuousReinforcementSchedule = CRF() -//let responseAction = PublishSubject() -//let startTimerAction = PublishSubject() -//let finishTimerAction = PublishSubject() -//var isSessionFlag = true -//let duringSR = BehaviorRelay(value: false) -//var disposeBag = DisposeBag() -// -//let respnseObservable = responseAction.response(timer) -// .do(onNext: { print("Response: \($0.numOfResponses), \($0.milliseconds)ms") }) -// -//let milliseconds = timer.milliseconds.shared -// .filter({ $0 % 1000 == 0 }) -// -//let firstStart = milliseconds.take(1) -// -//firstStart -// .do(onNext: { _ in print("Session started") }) -// .subscribe() -// .disposed(by: disposeBag) -// -//let timeObservable = milliseconds -// .do(onNext: { print("Time elapsed: \($0)ms") }) -// .map { ResponseEntity(numOfResponses: 0, milliseconds: $0) } -// .share(replay: 1) -// -//let reinforcementOn = Observable.merge( -// fixedTimeSchedule.decision(timeObservable), -// continuousReinforcementSchedule.decision(respnseObservable) -// ) -// .filter({ _ in !duringSR.value }) -// .filter({ $0.isReinforcement }) -// .share(replay: 1) -// -//let reinforcementOff = reinforcementOn -// .do(onNext: { print("SR on: \($0.entity.milliseconds)ms (IRI: \(trayOperatingDuration)ms)") }) -// .storeResponse(fixedTimeSchedule.dataStore.lastReinforcementEntity, condition: { $0.isReinforcement }) -// .extend(time: trayOperatingDuration, entities: fixedTimeSchedule.extendEntity) -// .flatMap { timer.delay(trayOperatingDuration, currentTime: $0.entity.milliseconds) } -// .do(onNext: { print("SR off: \($0)ms") }) -// .asObservable() -// .share(replay: 1) -// -//let nextTrial = Observable.merge( -// firstStart, -// reinforcementOff -// ) -// .do(onNext: { _ in updateInterval() }) -// .do(onNext: { print("ITI on: \($0)ms (Next ITI: \(nextInterval)ms)") }) -// .extend(time: { nextInterval }, entities: fixedTimeSchedule.extendEntity) -// .flatMap { timer.delay(nextInterval, currentTime: $0) } -// .do(onNext: { print("ITI off: \($0)ms") }) -// .asObservable() -// .share(replay: 1) -// -//nextTrial -// .do(onNext: { _ in print("SD on") }) -// .subscribe() -// .disposed(by: disposeBag) -// -//reinforcementOn -// .do(onNext: { _ in print("SD off") }) -// .subscribe() -// .disposed(by: disposeBag) -// -//reinforcementOff -// .count() -// .do(onNext: { print("Trial \($0)/\(numberOfPairings) finished") }) -// .filter({ $0 >= numberOfPairings }) -// .mapToVoid() -// .bind(to: finishTimerAction) -// .disposed(by: disposeBag) -// -//Observable.merge( -// reinforcementOn.map { _ in true }, -// reinforcementOff.map { _ in false } -// ) -// .bind(to: duringSR) -// .disposed(by: disposeBag) -// -//startTimerAction -// .flatMap { timer.start() } -// .subscribe() -// .disposed(by: disposeBag) -// -//finishTimerAction -// .flatMap { timer.finish() } -// .do(onNext: { print("Session finished: \($0)ms") }) -// .do(onNext: { _ in print("Program ended if enter any keys") }) -// .mapToVoid() -// .subscribe(onNext: { -// isSessionFlag = false -// disposeBag = DisposeBag() -// }) -// .disposed(by: disposeBag) -// -//startTimerAction.onNext(()) -//while isSessionFlag { -// let input = readLine() -// guard isSessionFlag else { continue } -// switch input { -// case "q": -// finishTimerAction.onNext(()) -// default: -// responseAction.onNext(()) -// } -//} diff --git a/OperantKitPlayground.playground/contents.xcplayground b/OperantKitPlayground.playground/contents.xcplayground deleted file mode 100644 index a93d484..0000000 --- a/OperantKitPlayground.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file