Class: StableMatch::Runner

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) {|_self| ... } ⇒ Runner

Returns a new instance of Runner.

Yields:

  • (_self)

Yield Parameters:



38
39
40
41
42
43
44
# File 'lib/stable_match/runner.rb', line 38

def initialize( *args , &block )
  options = Map.opts args
  @set1   = options.set1 rescue args.shift or raise ArgumentError.new( "No `set1` provided!" )
  @set2   = options.set2 rescue args.shift or raise ArgumentError.new( "No `set2` provided!" )

  yield self if block_given?
end

Class Method Details

.run(*args, &block) ⇒ Object

Runner::run

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



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

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

Instance Method Details

#build!Object

Runner#build!

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



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/stable_match/runner.rb', line 52

def build!
  set1.each do | target , options |
    candidate = Candidate.new target , *[ options ]
    candidates.push candidate
    candidate_set1[ target ] = candidate
  end

  set2.each do | target , options |
    candidate = Candidate.new target , *[ options ]
    candidates.push candidate
    candidate_set2[ target ] = candidate
  end

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

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

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

#builtObject Also known as: built?

Whether the sets have been built into candidate sets



5
# File 'lib/stable_match/runner.rb', line 5

fattr( :built ){ false }

#candidate_set1Object

The first set to use in the matching



19
# File 'lib/stable_match/runner.rb', line 19

fattr( :candidate_set1 ){ {} }

#candidate_set2Object

The second set to use in the matching



24
# File 'lib/stable_match/runner.rb', line 24

fattr( :candidate_set2 ){ {} }

#candidatesObject

Container for all the candidates



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

fattr( :candidates ){ [] }

#check!Object

Runner#check!

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



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/stable_match/runner.rb', line 84

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`!"
    error[ message ] unless \
    ## Anything there is a preference for is in the other set
    #
      ( options[ :preferences ].inject( true ){ | memo , preference | memo && 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`!"
    error[ message ] unless \
      ( options[ :preferences ].inject( true ){ | memo , preference | memo && set1_keys.include?( preference ) } )
  end

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

#checkedObject Also known as: checked?

Whether the sets have been checked for consistency



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

fattr( :checked ){ false }

#inspectObject



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/stable_match/runner.rb', line 114

def inspect
  require "yaml"

  inspection = proc do | set |
    set.keys.inject( Hash.new ) do | hash , key |
      candidate = set[ key ]
      preferences = candidate.preferences

      hash.update(
        key => {
          'matches'     => candidate.matches.map( &:target ),
          'preferences' => candidate.preferences.map( &:target ),
          'proposals'   => candidate.proposals.map( &:target )
        }
      )
    end
  end

  {
    'candidate_set1' => inspection[ candidate_set1 ],
    'candidate_set2' => inspection[ candidate_set2 ]
  }.to_yaml
end

#remaining_candidatesObject

Runner#remaining_candidates

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



144
145
146
# File 'lib/stable_match/runner.rb', line 144

def remaining_candidates
  candidates.reject{ | candidate | candidate.full? || candidate.exhausted_preferences? }
end

#runObject

Runner#run

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



154
155
156
157
158
159
160
161
162
163
# File 'lib/stable_match/runner.rb', line 154

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