Class: StableMatch::Runner

Inherits:
Object
  • Object
show all
Includes:
Util::InitializeWithDefaults
Defined in:
lib/stable_match/runner.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::InitializeWithDefaults

included

Constructor Details

#initialize(set1, set2, strategy = :symmetric) ⇒ Runner

Returns a new instance of Runner.



42
43
44
45
46
# File 'lib/stable_match/runner.rb', line 42

def initialize( set1 , set2 , strategy = :symmetric )
  @set1     = set1
  @set2     = set2
  @strategy = strategy
end

Instance Attribute Details

#builtObject Also known as: built?

Whether the sets have been built into candidate sets



9
10
11
# File 'lib/stable_match/runner.rb', line 9

def built
  @built
end

#candidate_set1Object

The first set to use in the matching



20
21
22
# File 'lib/stable_match/runner.rb', line 20

def candidate_set1
  @candidate_set1
end

#candidate_set2Object

The second set to use in the matching



25
26
27
# File 'lib/stable_match/runner.rb', line 25

def candidate_set2
  @candidate_set2
end

#candidatesObject

Container for all the candidates



13
14
15
# File 'lib/stable_match/runner.rb', line 13

def candidates
  @candidates
end

#checkedObject Also known as: checked?

Whether the sets have been checked for consistency



16
17
18
# File 'lib/stable_match/runner.rb', line 16

def checked
  @checked
end

#set1Object

The first set to use in the matching



20
21
22
# File 'lib/stable_match/runner.rb', line 20

def set1
  @set1
end

#set2Object

The second set to use in the matching



25
26
27
# File 'lib/stable_match/runner.rb', line 25

def set2
  @set2
end

#strategyObject

The way in which the run loop executes

Should be either: symmetric OR asymmetric



32
33
34
# File 'lib/stable_match/runner.rb', line 32

def strategy
  @strategy
end

Class Method Details

.run(*args) ⇒ Object

Class-level factory method to construct, check, build and run a Runner instance



35
36
37
38
39
40
# File 'lib/stable_match/runner.rb', line 35

def self.run( *args )
  runner = new *args
  runner.check!
  runner.build!
  runner.run
end

Instance Method Details

#build!Object

Convert set1 and set2 into candidate_set1 and candidate_set2 Also, track a master array of candidates Mark itself as built



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/stable_match/runner.rb', line 59

def build!
  set1.each do | target , options |
    candidate =
      Candidate.new \
        target,
        *( options.first.is_a?( Array ) ? options : [ options ] )

    candidates.push candidate
    candidate_set1[ target ] = candidate
  end

  set2.each do | target , options |
    candidate =
      Candidate.new \
        target,
        *( options.first.is_a?( Array ) ? options : [ options ] )

    candidates.push candidate
    candidate_set2[ target ] = candidate
  end

  candidate_set1.each do | target , candidate |
    candidate.preferences =
      candidate.raw_preferences.map { | preference_target | candidate_set2[ preference_target ] }
  end

  candidate_set2.each do | target , candidate |
    candidate.preferences =
      candidate.raw_preferences.map { | preference_target | candidate_set1[ preference_target ] }
  end

  # We've built the candidates
  self.built = true
end

#check!Object

Run basic checks against each raw set Meant to be run before being built into candidate sets Mark itself as checked



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/stable_match/runner.rb', line 97

def check!
  error     = proc { | message | raise ArgumentError.new( message ) }
  set1_keys = set1.keys
  set2_keys = set2.keys
  set1_size = set1.size
  set2_size = set2.size

  # Check set1
  set1.each do | target , options |
    message = "Preferences for #{ target.inspect } in `set1` do not match availabilities in `set2`!"
    options = options.first if options.first.is_a?( Array )
    error[ message ] unless \
      # Anything there is a preference for is in the other set
      ( options.all? { | preference | set2_keys.include?( preference ) } )
  end

  # Check set2 the same way
  set2.each do | target , options |
    message = "Preferences for #{ target.inspect } in `set2` do not match availabilities in `set1`!"
    options = options.first if options.first.is_a?( Array )
    error[ message ] unless \
      # Anything there is a preference for is in the other set
      ( options.all? { | preference | set1_keys.include?( preference ) } )
  end

  # We've run the check
  self.checked = true
end

#initialize_defaults!Object



48
49
50
51
52
53
54
# File 'lib/stable_match/runner.rb', line 48

def initialize_defaults!
  @built          ||= false
  @candidates     ||= []
  @checked        ||= false
  @candidate_set1 ||= {}
  @candidate_set2 ||= {}
end

#inspectObject Also known as: pretty_inspect



126
127
128
# File 'lib/stable_match/runner.rb', line 126

def inspect
  candidates.map( &:inspect ).join "\n\n"
end

#remaining_candidatesObject

This method respects the runner’s strategy!

List the remaining candidates that: -> have remaining slots available for matches AND -> have not already proposed to all of their preferences



139
140
141
142
143
144
145
146
# File 'lib/stable_match/runner.rb', line 139

def remaining_candidates
  case strategy.to_sym
  when :symmetric
    candidates.reject { | candidate | candidate.full? || candidate.exhausted_preferences? }
  when :asymmetric
    candidate_set1.values.reject { | candidate | candidate.full? || candidate.exhausted_preferences? }
  end
end

#runObject

While there are remaining candidates, ask each one to propose to all of their preferences until: -> a candidate has proposed to all of their preferences -> a candidate has no more matching_positions to be filled



151
152
153
154
155
156
157
158
159
160
# File 'lib/stable_match/runner.rb', line 151

def run
  while ( rcs = remaining_candidates ).any?
    rcs.each do | candidate |
      while !candidate.exhausted_preferences? && candidate.free?
        candidate.propose_to_next_preference
      end
    end
  end
  self
end