Skip to content

Commit fca67ea

Browse files
Merge pull request #100 from PyconUK/imports
Create converter.py in order to avoid circular imports
2 parents 5bcffc0 + fdc0aec commit fca67ea

File tree

8 files changed

+165
-164
lines changed

8 files changed

+165
-164
lines changed

docs/howto/obtain_mathematical_representation.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ different format.
66
Let us schedule a simple conference as described in :ref:`tutorial`::
77

88
>>> from conference_scheduler.resources import Slot, Event
9-
>>> from conference_scheduler import scheduler
9+
>>> from conference_scheduler import scheduler, converter
1010

1111
>>> slots = [Slot(venue='Big', starts_at='15-Sep-2016 09:30', duration=30, session="A", capacity=200),
1212
... Slot(venue='Big', starts_at='15-Sep-2016 10:00', duration=30, session="A", capacity=200)]
@@ -26,15 +26,15 @@ If we want to recover the mathematical array form of our solution (as described
2626
in :ref:`mathematical-model`), we use the :code:`scheduler.schedule_to_array`
2727
function::
2828

29-
>>> array = scheduler.schedule_to_array(schedule, events=events, slots=slots)
29+
>>> array = converter.schedule_to_array(schedule, events=events, slots=slots)
3030
>>> array
3131
array([[1, 0],
3232
[0, 1]], dtype=int8)
3333

3434
We can also return from a mathematical array to the schedule using the
3535
:code:`scheduler.array_to_schedule` function::
3636

37-
>>> for item in scheduler.array_to_schedule(array, events=events, slots=slots):
37+
>>> for item in converter.array_to_schedule(array, events=events, slots=slots):
3838
... print(f"{item.event.name} at {item.slot.starts_at} in {item.slot.venue}")
3939
Talk 1 at 15-Sep-2016 09:30 in Big
4040
Talk 2 at 15-Sep-2016 10:00 in Big
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""Convert a schedule between the three possible forms"""
2+
import numpy as np
3+
from conference_scheduler.resources import ScheduledItem
4+
5+
6+
def solution_to_array(solution, events, slots):
7+
"""Convert a schedule from solution to array form
8+
9+
Parameters
10+
----------
11+
solution : list or tuple
12+
of tuples of event index and slot index for each scheduled item
13+
events : list or tuple
14+
of :py:class:`resources.Event` instances
15+
slots : list or tuple
16+
of :py:class:`resources.Slot` instances
17+
18+
Returns
19+
-------
20+
np.array
21+
An E by S array (X) where E is the number of events and S the
22+
number of slots. Xij is 1 if event i is scheduled in slot j and
23+
zero otherwise
24+
25+
Example
26+
-------
27+
For For 3 events, 7 slots and the solution::
28+
29+
[(0, 1), (1, 4), (2, 5)]
30+
31+
The resulting array would be::
32+
33+
[[0, 1, 0, 0, 0, 0, 0],
34+
[0, 0, 0, 0, 1, 0, 0],
35+
[0, 0, 0, 0, 0, 1, 0]]
36+
"""
37+
array = np.zeros((len(events), len(slots)), dtype=np.int8)
38+
for item in solution:
39+
array[item[0], item[1]] = 1
40+
return array
41+
42+
43+
def solution_to_schedule(solution, events, slots):
44+
"""Convert a schedule from solution to schedule form
45+
46+
Parameters
47+
----------
48+
solution : list or tuple
49+
of tuples of event index and slot index for each scheduled item
50+
events : list or tuple
51+
of :py:class:`resources.Event` instances
52+
slots : list or tuple
53+
of :py:class:`resources.Slot` instances
54+
55+
Returns
56+
-------
57+
list
58+
A list of instances of :py:class:`resources.ScheduledItem`
59+
"""
60+
return [
61+
ScheduledItem(
62+
event=events[item[0]],
63+
slot=slots[item[1]]
64+
)
65+
for item in solution
66+
]
67+
68+
69+
def schedule_to_array(schedule, events, slots):
70+
"""Convert a schedule from schedule to array form
71+
72+
Parameters
73+
----------
74+
schedule : list or tuple
75+
of instances of :py:class:`resources.ScheduledItem`
76+
events : list or tuple
77+
of :py:class:`resources.Event` instances
78+
slots : list or tuple
79+
of :py:class:`resources.Slot` instances
80+
81+
Returns
82+
-------
83+
np.array
84+
An E by S array (X) where E is the number of events and S the
85+
number of slots. Xij is 1 if event i is scheduled in slot j and
86+
zero otherwise
87+
"""
88+
array = np.zeros((len(events), len(slots)), dtype=np.int8)
89+
for item in schedule:
90+
array[events.index(item.event), slots.index(item.slot)] = 1
91+
return array
92+
93+
94+
def array_to_schedule(array, events, slots):
95+
"""Convert a schedule from array to schedule form
96+
97+
Parameters
98+
----------
99+
array : np.array
100+
An E by S array (X) where E is the number of events and S the
101+
number of slots. Xij is 1 if event i is scheduled in slot j and
102+
zero otherwise
103+
events : list or tuple
104+
of :py:class:`resources.Event` instances
105+
slots : list or tuple
106+
of :py:class:`resources.Slot` instances
107+
108+
Returns
109+
-------
110+
list
111+
A list of instances of :py:class:`resources.ScheduledItem`
112+
"""
113+
scheduled = np.transpose(np.nonzero(array))
114+
return [
115+
ScheduledItem(event=events[item[0]], slot=slots[item[1]])
116+
for item in scheduled
117+
]

src/conference_scheduler/lp_problem/objective_functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from conference_scheduler.scheduler import schedule_to_array
1+
from conference_scheduler.converter import schedule_to_array
22

33

44
def capacity_demand_difference(slots, events, X, **kwargs):

src/conference_scheduler/scheduler.py

Lines changed: 7 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
"""Compute a schedule in one of three forms, convert a schedule between forms
2-
and compute the difference between .
1+
"""Compute a schedule in one of three forms and compute the difference between
2+
two schedules.
33
44
A schedule can be represented in one of three forms:
55
@@ -11,18 +11,18 @@
1111

1212
import pulp
1313
import numpy as np
14+
import conference_scheduler.converter as conv
1415
import conference_scheduler.lp_problem as lp
1516
import conference_scheduler.heuristics as heu
1617
import conference_scheduler.validator as val
1718
from conference_scheduler.resources import (
18-
ScheduledItem, Shape, ChangedEventScheduledItem, ChangedSlotScheduledItem
19+
Shape, ChangedEventScheduledItem, ChangedSlotScheduledItem
1920
)
2021

2122
# __all__ is defined so that we can control the order in which the functions
2223
# are documented by sphinx.
2324
__all__ = [
24-
'solution', 'array', 'schedule', 'solution_to_array',
25-
'solution_to_schedule', 'schedule_to_array', 'array_to_schedule',
25+
'solution', 'array', 'schedule',
2626
'event_schedule_difference', 'slot_schedule_difference']
2727

2828

@@ -185,7 +185,7 @@ def array(events, slots, objective_function=None, solver=None, **kwargs):
185185
[0, 0, 0, 0, 1, 0, 0],
186186
[0, 0, 0, 0, 0, 1, 0]]
187187
"""
188-
return solution_to_array(
188+
return conv.solution_to_array(
189189
solution(events, slots, objective_function, solver=solver, **kwargs),
190190
events, slots
191191
)
@@ -212,128 +212,12 @@ def schedule(events, slots, objective_function=None, solver=None, **kwargs):
212212
list
213213
A list of instances of :py:class:`resources.ScheduledItem`
214214
"""
215-
return solution_to_schedule(
215+
return conv.solution_to_schedule(
216216
solution(events, slots, objective_function, solver=solver, **kwargs),
217217
events, slots
218218
)
219219

220220

221-
# Functions to convert the schedule from one form to another
222-
223-
def solution_to_array(solution, events, slots):
224-
"""Convert a schedule from solution to array form
225-
226-
Parameters
227-
----------
228-
solution : list or tuple
229-
of tuples of event index and slot index for each scheduled item
230-
events : list or tuple
231-
of :py:class:`resources.Event` instances
232-
slots : list or tuple
233-
of :py:class:`resources.Slot` instances
234-
235-
Returns
236-
-------
237-
np.array
238-
An E by S array (X) where E is the number of events and S the
239-
number of slots. Xij is 1 if event i is scheduled in slot j and
240-
zero otherwise
241-
242-
Example
243-
-------
244-
For For 3 events, 7 slots and the solution::
245-
246-
[(0, 1), (1, 4), (2, 5)]
247-
248-
The resulting array would be::
249-
250-
[[0, 1, 0, 0, 0, 0, 0],
251-
[0, 0, 0, 0, 1, 0, 0],
252-
[0, 0, 0, 0, 0, 1, 0]]
253-
"""
254-
array = np.zeros((len(events), len(slots)), dtype=np.int8)
255-
for item in solution:
256-
array[item[0], item[1]] = 1
257-
return array
258-
259-
260-
def solution_to_schedule(solution, events, slots):
261-
"""Convert a schedule from solution to schedule form
262-
263-
Parameters
264-
----------
265-
solution : list or tuple
266-
of tuples of event index and slot index for each scheduled item
267-
events : list or tuple
268-
of :py:class:`resources.Event` instances
269-
slots : list or tuple
270-
of :py:class:`resources.Slot` instances
271-
272-
Returns
273-
-------
274-
list
275-
A list of instances of :py:class:`resources.ScheduledItem`
276-
"""
277-
return [
278-
ScheduledItem(
279-
event=events[item[0]],
280-
slot=slots[item[1]]
281-
)
282-
for item in solution
283-
]
284-
285-
286-
def schedule_to_array(schedule, events, slots):
287-
"""Convert a schedule from schedule to array form
288-
289-
Parameters
290-
----------
291-
schedule : list or tuple
292-
of instances of :py:class:`resources.ScheduledItem`
293-
events : list or tuple
294-
of :py:class:`resources.Event` instances
295-
slots : list or tuple
296-
of :py:class:`resources.Slot` instances
297-
298-
Returns
299-
-------
300-
np.array
301-
An E by S array (X) where E is the number of events and S the
302-
number of slots. Xij is 1 if event i is scheduled in slot j and
303-
zero otherwise
304-
"""
305-
array = np.zeros((len(events), len(slots)), dtype=np.int8)
306-
for item in schedule:
307-
array[events.index(item.event), slots.index(item.slot)] = 1
308-
return array
309-
310-
311-
def array_to_schedule(array, events, slots):
312-
"""Convert a schedule from array to schedule form
313-
314-
Parameters
315-
----------
316-
array : np.array
317-
An E by S array (X) where E is the number of events and S the
318-
number of slots. Xij is 1 if event i is scheduled in slot j and
319-
zero otherwise
320-
events : list or tuple
321-
of :py:class:`resources.Event` instances
322-
slots : list or tuple
323-
of :py:class:`resources.Slot` instances
324-
325-
Returns
326-
-------
327-
list
328-
A list of instances of :py:class:`resources.ScheduledItem`
329-
"""
330-
scheduled = np.transpose(np.nonzero(array))
331-
return [
332-
ScheduledItem(event=events[item[0]], slot=slots[item[1]])
333-
for item in scheduled
334-
]
335-
336-
337221
# Functions to compute the difference between two schedules
338222

339223

src/conference_scheduler/validator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from conference_scheduler import scheduler
1+
from conference_scheduler import converter
22
from conference_scheduler.lp_problem import constraints
33

44

@@ -75,7 +75,7 @@ def is_valid_solution(solution, events, slots):
7575
"""
7676
if len(solution) == 0:
7777
return False
78-
array = scheduler.solution_to_array(solution, events, slots)
78+
array = converter.solution_to_array(solution, events, slots)
7979
return is_valid_array(array, events, slots)
8080

8181

@@ -97,7 +97,7 @@ def solution_violations(solution, events, slots):
9797
of a list of strings indicating the nature of the violated
9898
constraints
9999
"""
100-
array = scheduler.solution_to_array(solution, events, slots)
100+
array = converter.solution_to_array(solution, events, slots)
101101
return array_violations(array, events, slots)
102102

103103

@@ -121,7 +121,7 @@ def is_valid_schedule(schedule, events, slots):
121121
"""
122122
if len(schedule) == 0:
123123
return False
124-
array = scheduler.schedule_to_array(schedule, events, slots)
124+
array = converter.schedule_to_array(schedule, events, slots)
125125
return is_valid_array(array, events, slots)
126126

127127

@@ -143,5 +143,5 @@ def schedule_violations(schedule, events, slots):
143143
of a list of strings indicating the nature of the violated
144144
constraints
145145
"""
146-
array = scheduler.schedule_to_array(schedule, events, slots)
146+
array = converter.schedule_to_array(schedule, events, slots)
147147
return array_violations(array, events, slots)

tests/lp_problem/test_objective_functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np
22
from conference_scheduler.lp_problem import objective_functions as of
3-
from conference_scheduler.scheduler import array_to_schedule
3+
from conference_scheduler.converter import array_to_schedule
44

55

66
def test_capacity_demand_difference(slots, events, X):

tests/test_converter.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import numpy as np
2+
from conference_scheduler import converter
3+
4+
5+
def test_solution_to_array(valid_solution, valid_array, events, slots):
6+
array = converter.solution_to_array(valid_solution, events, slots)
7+
assert np.array_equal(array, valid_array)
8+
assert all([isinstance(x, np.int8) for x in array.flat])
9+
10+
11+
def test_solution_to_schedule(valid_solution, valid_schedule, events, slots):
12+
schedule = converter.solution_to_schedule(valid_solution, events, slots)
13+
assert type(schedule) is list
14+
assert list(schedule) == valid_schedule
15+
16+
17+
def test_schedule_to_array(valid_schedule, valid_array, events, slots):
18+
array = converter.schedule_to_array(valid_schedule, events, slots)
19+
assert np.array_equal(array, valid_array)
20+
assert all([isinstance(x, np.int8) for x in array.flat])
21+
22+
23+
def test_array_to_schedule(valid_schedule, valid_array, events, slots):
24+
schedule = list(
25+
converter.array_to_schedule(valid_array, events, slots)
26+
)
27+
assert type(schedule) is list
28+
assert schedule == valid_schedule

0 commit comments

Comments
 (0)