@@ -55,95 +55,95 @@ stack - if the stack is then empty, then there is no solution.
5555
5656The pseudocode for a solve looks like this (and yes, you will have to read the
5757solver code for full appreciation of what's going on here):
58+ ``` python
59+ def solve (requests ):
60+ phase = create_initial_phase(requests)
61+ phase_stack = stack()
62+ phase_stack.push(phase)
63+
64+ while not solved():
65+ phase = phase_stack.pop()
66+
67+ if phase.failed:
68+ phase = phase_stack.pop() # discard previous failed phase
69+
70+ if phase.exhausted:
71+ phase, next_phase = phase.split()
72+ phase_stack.push(next_phase)
73+
74+ new_phase = solve_phase(phase)
75+
76+ if new_phase.failed:
77+ phase_stack.push(new_phase) # we keep last fail on the stack
78+ elif new_phase.solved:
79+ # some housekeeping here, like checking for cycles
80+ final_phase = finalise_phase(new_phase)
81+ phase_stack.push(final_phase)
82+ else :
83+ phase_stack.push(new_phase) # phase is exhausted
84+
85+ def solve_phase (phase ):
86+ while True :
87+ changed_scopes = []
88+ added_scopes = []
89+ widened_scopes = []
5890
59- def solve(requests):
60- phase = create_initial_phase(requests)
61- phase_stack = stack()
62- phase_stack.push(phase)
63-
64- while not solved():
65- phase = phase_stack.pop()
66-
67- if phase.failed:
68- phase = phase_stack.pop() # discard previous failed phase
69-
70- if phase.exhausted:
71- phase, next_phase = phase.split()
72- phase_stack.push(next_phase)
73-
74- new_phase = solve_phase(phase)
75-
76- if new_phase.failed:
77- phase_stack.push(new_phase) # we keep last fail on the stack
78- elif new_phase.solved:
79- # some housekeeping here, like checking for cycles
80- final_phase = finalise_phase(new_phase)
81- phase_stack.push(final_phase)
82- else:
83- phase_stack.push(new_phase) # phase is exhausted
84-
85- def solve_phase(phase):
8691 while True :
87- changed_scopes = []
88- added_scopes = []
89- widened_scopes = []
92+ extractions = []
9093
91- while True :
92- extractions = []
94+ foreach phase.scope as scope :
95+ extractions |= collect_extractions(scope)
9396
94- foreach phase.scope as scope:
95- extractions |= collect_extractions(scope)
97+ if not extractions:
98+ break
99+
100+ merge(extractions)
101+ if in_conflict(extractions):
102+ set_fail()
103+ return
96104
97- if not extractions :
98- break
105+ foreach phase.scope as scope :
106+ intersect(scope, extractions)
99107
100- merge(extractions)
101- if in_conflict(extractions):
108+ if failed(scope):
102109 set_fail()
103110 return
104111
105- foreach phase.scope as scope:
106- intersect(scope, extractions)
107-
108- if failed(scope):
109- set_fail()
110- return
111-
112- if was_intersected(scope):
113- changed_scopes.add(scope)
114-
115- if was_widened(scope):
116- widened_scopes.add(scope)
112+ if was_intersected(scope):
113+ changed_scopes.add(scope)
117114
118- # get those extractions involving new packages
119- new_extractions = get_new_extractions(extractions )
115+ if was_widened(scope):
116+ widened_scopes.add(scope )
120117
121- # add them as new scopes
122- foreach request in new_extractions:
123- scope = new_scope(request)
124- added_scopes.add(scope)
125- phase.add(scope)
118+ # get those extractions involving new packages
119+ new_extractions = get_new_extractions(extractions)
126120
127- if no (changed_scopes or added_scopes or widened_scopes):
128- break
121+ # add them as new scopes
122+ foreach request in new_extractions:
123+ scope = new_scope(request)
124+ added_scopes.add(scope)
125+ phase.add(scope)
129126
130- pending_reductions = convert_to_reduction_set(
131- changed_scopes, added_scopes, widened_scopes)
127+ if not (changed_scopes or added_scopes or widened_scopes):
128+ break
132129
133- while pending_reductions:
134- scope_a, scope_b = pending_reductions.pop()
135- scope_a.reduce_by(scope_b)
130+ pending_reductions = convert_to_reduction_set(
131+ changed_scopes, added_scopes, widened_scopes)
136132
137- if totally_reduced(scope_a) :
138- set_fail ()
139- return
133+ while pending_reductions :
134+ scope_a, scope_b = pending_reductions.pop ()
135+ scope_a.reduce_by(scope_b)
140136
141- # scope_a changed so other scopes need to reduce against it again
142- if was_reduced(scope_a):
143- foreach phase.scope as scope:
144- if scope is not scope_a:
145- pending_reductions.add(scope, scope_a)
137+ if totally_reduced(scope_a):
138+ set_fail()
139+ return
146140
141+ # scope_a changed so other scopes need to reduce against it again
142+ if was_reduced(scope_a):
143+ foreach phase.scope as scope:
144+ if scope is not scope_a:
145+ pending_reductions.add(scope, scope_a)
146+ ```
147147There are 2 notable points missing from the pseudocode, related to optimisations:
148148
149149* Scopes keep a set of package families so that they can quickly skip unnecessary
0 commit comments