schedsolver2 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/.gitignore +23 -0
  2. data/Gemfile +4 -0
  3. data/LICENCE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +1 -0
  6. data/features/schedsolver_T1_initializes.feature +11 -0
  7. data/features/schedsolver_T2_seed.feature +16 -0
  8. data/features/schedsolver_T3_constraint_checker.feature +29 -0
  9. data/features/schedsolver_T3v2_constraints.feature +8 -0
  10. data/features/schedsolver_T4_print_attributes.feature +19 -0
  11. data/features/schedsolver_T5_crud_attributes.feature +26 -0
  12. data/features/schedsolver_T6_generate_schedules.feature +14 -0
  13. data/features/schedsolver_T7_log_output.feature +9 -0
  14. data/features/schedsolver_T8_big_example.feature +10 -0
  15. data/features/schedsolver_heuristic.feature +10 -0
  16. data/features/step_definitions/T1_steps.rb +19 -0
  17. data/features/step_definitions/T3_steps.rb +97 -0
  18. data/features/step_definitions/T3v2_steps.rb +14 -0
  19. data/features/step_definitions/T4_steps.rb +19 -0
  20. data/features/step_definitions/T6_steps.rb +62 -0
  21. data/features/step_definitions/heuristic_steps.rb +49 -0
  22. data/features/step_definitions/shared_steps.rb +10 -0
  23. data/features/support/env.rb +4 -0
  24. data/features/support/shared_contexts.rb +47 -0
  25. data/lib/schedsolver2.rb +84 -0
  26. data/lib/schedsolver2/ClassCounter.rb +42 -0
  27. data/lib/schedsolver2/constraint.rb +133 -0
  28. data/lib/schedsolver2/schedule.rb +107 -0
  29. data/lib/schedsolver2/school.rb +176 -0
  30. data/lib/schedsolver2/teacher.rb +49 -0
  31. data/schedsolver2.gemspec +23 -0
  32. data/script/console +10 -0
  33. data/script/destroy +14 -0
  34. data/script/generate +14 -0
  35. data/spec/ClassCounter_spec.rb +38 -0
  36. data/spec/constraint_spec.rb +83 -0
  37. data/spec/schedsolver2_spec.rb +4 -0
  38. data/spec/schedule_spec.rb +53 -0
  39. data/spec/school_spec.rb +56 -0
  40. data/spec/spec.opts +1 -0
  41. data/spec/spec_helper.rb +3 -0
  42. data/spec/support/masters/2ETs_8_to_14_by_1.schedule +12 -0
  43. data/spec/support/shared_contexts.rb +41 -0
  44. data/spec/teacher_spec.rb +43 -0
  45. metadata +151 -0
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ !.gitignore
2
+ .*
3
+ *.log
4
+ *.gem
5
+ *.rbc
6
+ .bundle
7
+ .config
8
+ coverage
9
+ InstalledFiles
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
17
+
18
+ test_script.rb
19
+ test_logger.rb
20
+
21
+ .yardoc
22
+ _yardoc
23
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in schedsolver2.gemspec
4
+ gemspec
data/LICENCE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Julian Irwin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Schedsolver2
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'schedsolver2'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install schedsolver2
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,11 @@
1
+ #This is a trivial feature, existed to get me warmed up
2
+ @completed
3
+ Feature: T1 - Programmer Inits Schedsolver
4
+ I want to open schedsolver
5
+ So that I can generate a schedule
6
+ @completed
7
+ Scenario: Initialize a School Instance
8
+ Given I haven't yet initialized schedsolver
9
+ When I have Teachers, SchoolInfo and Constraints
10
+ And I initialize a School instance
11
+ Then The instance should have the inputs and empty population
@@ -0,0 +1,16 @@
1
+ @not_implemented
2
+ Feature: T2 - Seed
3
+ As a user of algorithm api
4
+ I want to create an initial population by calling Schedsolver#seed_population
5
+ So that the genetic algorithm has something to run on
6
+ Scenario: Generate Empty Seeds
7
+ Given I have an initialized School
8
+ When I add some schedules
9
+ Then the schools schedules list should get some empty schedules
10
+ Scenario: Fill Seeds
11
+ Given I have an initialized School
12
+ And it has some empty schedules
13
+ When I call School#fill_seeds
14
+ Then The population should be filled with seed schedules
15
+
16
+
@@ -0,0 +1,29 @@
1
+ @not-implemented
2
+ Feature: T3 - Constraint Checker
3
+ I am an Algorithm *bleep bloop bleep*
4
+ I want to check if the schedule I just generated conforms to constraints
5
+ So that my creator will be satisfied *bloop*
6
+ Scenario: HC - Part Time Hours
7
+ Given I have an initialized School
8
+ And It has "2" schedule
9
+ And a part time art teacher constraint (M and 8-11 Tu)
10
+ When homeroom teacher gets scheduled for art on Tuesday in the first schedule
11
+ And homeroom teacher isn't scheduled for art on Tuesday or Monday in the second schedule
12
+ Then the constraint asserter will fail for the first schedule
13
+ And the constraint asserter will pass for the second schedule
14
+ Scenario: HC - Exact EC’s Per Week
15
+ Given I have an initialized School
16
+ And It has "3" schedules
17
+ And each homeroom must have "4" EC's per week
18
+ When the first schedule has 3 EC's, the second has 4 and the last has 5
19
+ Then only the middle schedule will pass the constraint asserter
20
+ Scenario: HC - Max EC’s Per Day
21
+ Given I have an initialized School
22
+ And It has "2" schedules
23
+ And a homeroom (:One) can have a max of two EC's per day
24
+ When one schedule has 3 EC's on monday and the other has 2
25
+ Then the first will fail and the second will succeed
26
+ Scenario: Multiple Constraints applied to one schedule
27
+ Given I have an initialized School
28
+ And It has "2" schedules
29
+ Scenario: SC - Spacing Requirements
@@ -0,0 +1,8 @@
1
+ Feature: Constraints
2
+ @wip
3
+ @heuristic
4
+ Scenario: Adding a part time hours constraint
5
+ Given I have an initialized School
6
+ And there is a teacher who only works on MWF
7
+ When the schedule is generated
8
+ Then the teacher will not be schedules on those days
@@ -0,0 +1,19 @@
1
+ Feature: T4. Print School Attributes
2
+ I am a software developer
3
+ I want to print out schedules as an ASCII table
4
+ So that I can get feedback while developing/tweaking the Scheduling Algorithm
5
+ @completed
6
+ Scenario: Print schedules
7
+ Given I have an initialized School
8
+ When I call #print "schedules"
9
+ Then All of the schedules in population will be printed to my screen
10
+ @completed
11
+ Scenario: Print constraints
12
+ Given I have an initialized School
13
+ When I call #print "constraints"
14
+ Then the constraints will be displayed in a readable fashion
15
+ @completed
16
+ Scenario: Print school info
17
+ Given I have an initialized School
18
+ When I call #print "school_info"
19
+ Then the info will be displayed in a readable fashion
@@ -0,0 +1,26 @@
1
+ @not_implemented
2
+ Feature: T5. CRUD School Attributes
3
+ I am a User
4
+ I want to change an attribute of my School
5
+ So that I can easily keep my schedule parameters up to date.
6
+ # Scenario: Add Teacher Given I have an initialized School
7
+ # Given I have an initialized School
8
+ # When I call Add Mrs. Two to ETs
9
+ # Then the teacher will be in School.teachers[:enrichment]
10
+ # Scenario: Delete Teacher
11
+ # Given I have an initialized School
12
+ # When I call Delete Mr. Four
13
+ # Then the teacher will not be in School.teachers[:homeroom]
14
+ # Scenario: Add Constraint - ET Hours
15
+ # Given I have an initialized School
16
+ # And a Teacher, Mr. MWTh, in that school that can only work M, W, Th
17
+ # When I add a HC dictating Mr. MWTh’s hours
18
+ # Then MR. MWTh will only be scheduled on M, W, Th
19
+ # Scenario: Delete Constraint
20
+ # Given I have an initialized School
21
+ # When I call Delete Constraint about Mr. MWTh
22
+ # Then the constraint will not show up when constraints are searched
23
+ Scenario: Add teacher
24
+ Given I have an initialized School
25
+ When I call "add" "e_teacher" "MrsTwo"
26
+ Then the "teachers" "e_teacher" list "should" contain "MrsTwo"
@@ -0,0 +1,14 @@
1
+ @not_implemented
2
+ Feature: T6. Run Schedule Generator
3
+ I am a User
4
+ I want to generate a schedule for my elementary school
5
+ So that I don’t have to do it by hand!
6
+ @big_example
7
+ Scenario: Small example generation of schedule
8
+ Given I have a school with ET 0 and HT 1
9
+ And ET 0 works only Tuesday, Thursday
10
+ And HT 1 must have 4 ECs/wk, 2/dy
11
+ When I generate a schedule
12
+ Then HT will have two ECs on both Tuesday and Thursday
13
+
14
+
@@ -0,0 +1,9 @@
1
+ @not_implemented
2
+ Feature: T7. Developer Logs Output
3
+ I am a Developer
4
+ I want to debug and monitor Schedsolver
5
+ So that I can fix bugs and make faster more organized progress
6
+ Scenario: Automatic Log Outpus
7
+ Given I have an initialized School
8
+ When I run the algorithm
9
+ Then I should get informative log output (FIXME more details)
@@ -0,0 +1,10 @@
1
+ Feature:
2
+ I am the rails app
3
+ I want to find a valid schedule
4
+ So that I can satisfy the users request
5
+ @big_example
6
+ Scenario:
7
+ Given I have a big example school with several constraints
8
+ When two schedules, first valid, second invalid are added
9
+ Then the first will fail and the second will succeed
10
+
@@ -0,0 +1,10 @@
1
+ Feature: Heuristic approach
2
+ @completed
3
+ Scenario:
4
+ Given I have an initialized School
5
+ And the school's 0th ET works MWF
6
+ And each HT must have 3 ECs/wk
7
+ And each HT may have at most 2 ECs/dy
8
+ When the schedule is generated
9
+ Then there wil be one EC on each of MWF for ET 0
10
+ And there will be three total ET 1 entries
@@ -0,0 +1,19 @@
1
+ Given /^I haven't yet initialized schedsolver$/ do
2
+ end
3
+
4
+ When /^I have Teachers, SchoolInfo and Constraints$/ do
5
+ @si.should_not == nil
6
+ @cs.should_not == nil
7
+ @ts.should_not == nil
8
+ end
9
+
10
+ When /^I initialize a School instance$/ do
11
+ @school = Schedsolver2::School.new @si, @ts, @cs
12
+ end
13
+
14
+ Then /^The instance should have the inputs and empty population$/ do
15
+ @school.scheds.should == []
16
+ @school.consts.should_not == nil
17
+ end
18
+
19
+
@@ -0,0 +1,97 @@
1
+ #################Part Time Hours###################
2
+
3
+ Given /^a part time art teacher constraint \(M and 8-11 Tu\)$/ do
4
+ # All day monday and tuesday
5
+ not_working_days = {}
6
+ [:mon, :tue].each do |day|
7
+ not_working_days[day] ||= {}
8
+ (8...14).each do |time|
9
+ not_working_days[day][time] = [0]
10
+ end
11
+ end
12
+ # Pass as long as :Art isn't scheduled on mon or tue.
13
+ test = Proc.new do |slot, value|
14
+ if value == nil then false else true end
15
+ end
16
+ #
17
+ counter = Proc.new do |count|
18
+ if count > 0 then false else true end
19
+ end
20
+
21
+ hc = Schedsolver2::Constraint.new([not_working_days], test, counter)
22
+
23
+ @school.add :hard_constraint, hc
24
+ end
25
+
26
+ When /^homeroom teacher gets scheduled for art on Tuesday in the first schedule$/ do
27
+ @school.scheds[0][:tue, 8, 0] = 2
28
+ end
29
+
30
+ When /^homeroom teacher isn't scheduled for art on Tuesday or Monday in the second schedule$/ do
31
+ @school.scheds[1][:wed, 8, 0] = 2
32
+ end
33
+
34
+ Then /^the constraint asserter will fail for the first schedule$/ do
35
+ Schedsolver2::Constraint.hard_assert(@school.scheds[0], @school.cs[:h][0]).should == false
36
+ end
37
+
38
+ Then /^the constraint asserter will pass for the second schedule$/ do
39
+ Schedsolver2::Constraint.hard_assert(@school.scheds[1], @school.cs[:h][0]).should == true
40
+ end
41
+
42
+ ################# Exact EC's Per Week ###############
43
+
44
+ Given /^each homeroom must have "(.*?)" EC's per week$/ do |arg1|
45
+ s_d = @all_days_slot_descriptor
46
+ test = Proc.new { |slot, value| if value == nil then false else true end}
47
+ assess = Proc.new { |count| if count == 4 then true else false end}
48
+ c = Schedsolver2::Constraint.new [s_d], test, assess
49
+ @school.add :hard_constraint, c
50
+ end
51
+
52
+ When /^the first schedule has (\d+) EC's, the second has (\d+) and the last has (\d+)$/ do |arg1, arg2, arg3|
53
+ start = @si[:start_time]
54
+ [arg1, arg2, arg3].each_with_index do |arg, n_sch|
55
+ (0..arg.to_i-1).each do |n|
56
+ @school.scheds[n_sch][:mon, start + n, 0] = 2
57
+ end
58
+ end
59
+ @school.print :schedules
60
+ end
61
+
62
+ Then /^only the middle schedule will pass the constraint asserter$/ do
63
+ Schedsolver2::Constraint.hard_assert(@school.scheds[0], @school.cs[:h][0]).should == false
64
+ Schedsolver2::Constraint.hard_assert(@school.scheds[1], @school.cs[:h][0]).should == true
65
+ Schedsolver2::Constraint.hard_assert(@school.scheds[2], @school.cs[:h][0]).should == false
66
+ end
67
+
68
+ ################# Exact EC's Per Week ###############
69
+
70
+ Given /^a homeroom \(:One\) can have a max of two EC's per day$/ do
71
+ s_ds = []
72
+ @school.days.each do |day|
73
+ s_ds << Schedsolver2::Constraint.day_descriptor(day, @school.times, @school.et_ids)
74
+ end
75
+ test = Proc.new {|slot, value| if value == 2 then true else false end }
76
+ assess = Proc.new {|count| if count <= 2 then true else false end}
77
+ c = Schedsolver2::Constraint.new s_ds, test, assess
78
+ @school.add :hard_constraint, c
79
+ end
80
+
81
+ When /^one schedule has (\d+) EC's on monday and the other has (\d+)$/ do |a1, a2|
82
+ @school.scheds[0][:mon, 8, 0] = 2
83
+ @school.scheds[0][:mon, 9, 0] = 2
84
+ @school.scheds[0][:mon, 14, 1] = 2
85
+ @school.scheds[1][:mon, 8, 0] = 2
86
+ @school.scheds[1][:mon, 14, 1] = 2
87
+ end
88
+
89
+ Then /^the first will fail and the second will succeed$/ do
90
+ Schedsolver2.log.info("et_ids: #{@school.et_ids}")
91
+ Schedsolver2::Constraint.hard_assert(@school.scheds[0], @school.cs[:h][0]).should == false
92
+ Schedsolver2::Constraint.hard_assert(@school.scheds[1], @school.cs[:h][0]).should == true
93
+ end
94
+
95
+ ################# Sanity Checks #######################
96
+
97
+
@@ -0,0 +1,14 @@
1
+ Given /^there is a teacher who only works on MWF$/ do
2
+ @school.ts[:e][0].work_days = [:mon, :wed, :fri]
3
+ @school.parse_part_time_constraints
4
+ end
5
+
6
+ Then /^the teacher will not be schedules on those days$/ do
7
+ id = @school.ts[:e][0].id
8
+ @school.print :constraints
9
+ Schedsolver2::Constraint.hard_assert(
10
+ @school.scheds[0],
11
+ @school.cs[:part_time][id]
12
+ ).should == true
13
+ end
14
+
@@ -0,0 +1,19 @@
1
+ # Print Schedules
2
+ #
3
+ When /^I call \#print "(.*?)"$/ do |arg1|
4
+ @school.print arg1
5
+ end
6
+
7
+ Then /^All of the schedules in population will be printed to my screen$/ do
8
+ output = double()
9
+ @school.log = output
10
+ output.should_receive(:info)
11
+ @school.add :schedules, 1
12
+ @school.print :schedules
13
+ end
14
+
15
+ Then /^the info will be displayed in a readable fashion$/ do
16
+ end
17
+
18
+ Then /^the constraints will be displayed in a readable fashion$/ do
19
+ end
@@ -0,0 +1,62 @@
1
+ Given /^I have a school with ET (\d+) and HT (\d+)$/ do |arg1, arg2|
2
+ @si = {:start_time => 8,
3
+ :end_time => 15,
4
+ :num_blocks => 14,
5
+ :block_size => 0.5}
6
+ @ts = {:e => [Schedsolver2::Teacher.new(:Art, 0)],
7
+ :h => [Schedsolver2::Teacher.new(:One, 1)]}
8
+ @cs = {:h => [], :s => []}
9
+ @school = Schedsolver2::School.new @si, @ts, @cs
10
+ @school.add :schedules, 1
11
+ @school.log.level = Logger::INFO
12
+ end
13
+
14
+ Given /^ET (\d+) works only Tuesday, Thursday$/ do |arg1|
15
+ s_ds = [:mon, :wed, :fri].inject([]) do |ds, day|
16
+ ds << Schedsolver2::Constraint.day_descriptor(day, @school.times, [0])
17
+ end
18
+ @school.log.debug("s_ds: #{s_ds}")
19
+ test = Proc.new {|slot, value| if value != nil then true else false end}
20
+ assess = Proc.new {|count| if count > 0 then false else true end}
21
+ hc0 = Schedsolver2::Constraint.new s_ds, test, assess
22
+ @school.add :hard_constraint, hc0
23
+ end
24
+
25
+ Given /^HT (\d+) must have (\d+) ECs\/wk, (\d+)\/dy$/ do |arg1, arg2, arg3|
26
+ s_ds0 = [Schedsolver2::Constraint.week_descriptor(@school.times, [0])]
27
+ s_ds1 = [:mon, :tue, :wed, :thu, :fri].inject([]) do |ds, day|
28
+ ds << Schedsolver2::Constraint.day_descriptor(day, @school.times, [0])
29
+ end
30
+
31
+ @school.log.debug "s_ds0: #{s_ds0}"
32
+ @school.log.debug "s_ds1: #{s_ds1}"
33
+
34
+ test = Proc.new {|slot, value| if value == 1 then true else false end}
35
+
36
+ assess0 = Proc.new {|count| if count == 4 then true else false end}
37
+ assess1 = Proc.new {|count| if count <= 2 then true else false end}
38
+
39
+ hc0 = Schedsolver2::Constraint.new s_ds0, test, assess0
40
+ hc1 = Schedsolver2::Constraint.new s_ds1, test, assess1
41
+
42
+ @school.add :hard_constraint, hc0
43
+ @school.add :hard_constraint, hc1
44
+ end
45
+
46
+ When /^I generate a schedule$/ do
47
+ @school.make_schedule(0)
48
+ end
49
+
50
+ Then /^HT will have two ECs on both Tuesday and Thursday$/ do
51
+ Schedsolver2::Constraint.hard_assert(@school.scheds[0], @school.cs[:h][0]).should == true
52
+ Schedsolver2::Constraint.hard_assert(@school.scheds[0], @school.cs[:h][2]).should == true
53
+ Schedsolver2::Constraint.hard_assert(@school.scheds[0], @school.cs[:h][1]).should == true
54
+ end
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+