Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create converter.py in order to avoid circular imports #100

Merged
merged 1 commit into from
Aug 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/howto/obtain_mathematical_representation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ different format.
Let us schedule a simple conference as described in :ref:`tutorial`::

>>> from conference_scheduler.resources import Slot, Event
>>> from conference_scheduler import scheduler
>>> from conference_scheduler import scheduler, converter

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

>>> array = scheduler.schedule_to_array(schedule, events=events, slots=slots)
>>> array = converter.schedule_to_array(schedule, events=events, slots=slots)
>>> array
array([[1, 0],
[0, 1]], dtype=int8)

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

>>> for item in scheduler.array_to_schedule(array, events=events, slots=slots):
>>> for item in converter.array_to_schedule(array, events=events, slots=slots):
... print(f"{item.event.name} at {item.slot.starts_at} in {item.slot.venue}")
Talk 1 at 15-Sep-2016 09:30 in Big
Talk 2 at 15-Sep-2016 10:00 in Big
117 changes: 117 additions & 0 deletions src/conference_scheduler/converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Convert a schedule between the three possible forms"""
import numpy as np
from conference_scheduler.resources import ScheduledItem


def solution_to_array(solution, events, slots):
"""Convert a schedule from solution to array form

Parameters
----------
solution : list or tuple
of tuples of event index and slot index for each scheduled item
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
np.array
An E by S array (X) where E is the number of events and S the
number of slots. Xij is 1 if event i is scheduled in slot j and
zero otherwise

Example
-------
For For 3 events, 7 slots and the solution::

[(0, 1), (1, 4), (2, 5)]

The resulting array would be::

[[0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0]]
"""
array = np.zeros((len(events), len(slots)), dtype=np.int8)
for item in solution:
array[item[0], item[1]] = 1
return array


def solution_to_schedule(solution, events, slots):
"""Convert a schedule from solution to schedule form

Parameters
----------
solution : list or tuple
of tuples of event index and slot index for each scheduled item
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
list
A list of instances of :py:class:`resources.ScheduledItem`
"""
return [
ScheduledItem(
event=events[item[0]],
slot=slots[item[1]]
)
for item in solution
]


def schedule_to_array(schedule, events, slots):
"""Convert a schedule from schedule to array form

Parameters
----------
schedule : list or tuple
of instances of :py:class:`resources.ScheduledItem`
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
np.array
An E by S array (X) where E is the number of events and S the
number of slots. Xij is 1 if event i is scheduled in slot j and
zero otherwise
"""
array = np.zeros((len(events), len(slots)), dtype=np.int8)
for item in schedule:
array[events.index(item.event), slots.index(item.slot)] = 1
return array


def array_to_schedule(array, events, slots):
"""Convert a schedule from array to schedule form

Parameters
----------
array : np.array
An E by S array (X) where E is the number of events and S the
number of slots. Xij is 1 if event i is scheduled in slot j and
zero otherwise
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
list
A list of instances of :py:class:`resources.ScheduledItem`
"""
scheduled = np.transpose(np.nonzero(array))
return [
ScheduledItem(event=events[item[0]], slot=slots[item[1]])
for item in scheduled
]
2 changes: 1 addition & 1 deletion src/conference_scheduler/lp_problem/objective_functions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from conference_scheduler.scheduler import schedule_to_array
from conference_scheduler.converter import schedule_to_array


def capacity_demand_difference(slots, events, X, **kwargs):
Expand Down
130 changes: 7 additions & 123 deletions src/conference_scheduler/scheduler.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Compute a schedule in one of three forms, convert a schedule between forms
and compute the difference between .
"""Compute a schedule in one of three forms and compute the difference between
two schedules.

A schedule can be represented in one of three forms:

Expand All @@ -11,18 +11,18 @@

import pulp
import numpy as np
import conference_scheduler.converter as conv
import conference_scheduler.lp_problem as lp
import conference_scheduler.heuristics as heu
import conference_scheduler.validator as val
from conference_scheduler.resources import (
ScheduledItem, Shape, ChangedEventScheduledItem, ChangedSlotScheduledItem
Shape, ChangedEventScheduledItem, ChangedSlotScheduledItem
)

# __all__ is defined so that we can control the order in which the functions
# are documented by sphinx.
__all__ = [
'solution', 'array', 'schedule', 'solution_to_array',
'solution_to_schedule', 'schedule_to_array', 'array_to_schedule',
'solution', 'array', 'schedule',
'event_schedule_difference', 'slot_schedule_difference']


Expand Down Expand Up @@ -185,7 +185,7 @@ def array(events, slots, objective_function=None, solver=None, **kwargs):
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0]]
"""
return solution_to_array(
return conv.solution_to_array(
solution(events, slots, objective_function, solver=solver, **kwargs),
events, slots
)
Expand All @@ -212,128 +212,12 @@ def schedule(events, slots, objective_function=None, solver=None, **kwargs):
list
A list of instances of :py:class:`resources.ScheduledItem`
"""
return solution_to_schedule(
return conv.solution_to_schedule(
solution(events, slots, objective_function, solver=solver, **kwargs),
events, slots
)


# Functions to convert the schedule from one form to another

def solution_to_array(solution, events, slots):
"""Convert a schedule from solution to array form

Parameters
----------
solution : list or tuple
of tuples of event index and slot index for each scheduled item
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
np.array
An E by S array (X) where E is the number of events and S the
number of slots. Xij is 1 if event i is scheduled in slot j and
zero otherwise

Example
-------
For For 3 events, 7 slots and the solution::

[(0, 1), (1, 4), (2, 5)]

The resulting array would be::

[[0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0]]
"""
array = np.zeros((len(events), len(slots)), dtype=np.int8)
for item in solution:
array[item[0], item[1]] = 1
return array


def solution_to_schedule(solution, events, slots):
"""Convert a schedule from solution to schedule form

Parameters
----------
solution : list or tuple
of tuples of event index and slot index for each scheduled item
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
list
A list of instances of :py:class:`resources.ScheduledItem`
"""
return [
ScheduledItem(
event=events[item[0]],
slot=slots[item[1]]
)
for item in solution
]


def schedule_to_array(schedule, events, slots):
"""Convert a schedule from schedule to array form

Parameters
----------
schedule : list or tuple
of instances of :py:class:`resources.ScheduledItem`
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
np.array
An E by S array (X) where E is the number of events and S the
number of slots. Xij is 1 if event i is scheduled in slot j and
zero otherwise
"""
array = np.zeros((len(events), len(slots)), dtype=np.int8)
for item in schedule:
array[events.index(item.event), slots.index(item.slot)] = 1
return array


def array_to_schedule(array, events, slots):
"""Convert a schedule from array to schedule form

Parameters
----------
array : np.array
An E by S array (X) where E is the number of events and S the
number of slots. Xij is 1 if event i is scheduled in slot j and
zero otherwise
events : list or tuple
of :py:class:`resources.Event` instances
slots : list or tuple
of :py:class:`resources.Slot` instances

Returns
-------
list
A list of instances of :py:class:`resources.ScheduledItem`
"""
scheduled = np.transpose(np.nonzero(array))
return [
ScheduledItem(event=events[item[0]], slot=slots[item[1]])
for item in scheduled
]


# Functions to compute the difference between two schedules


Expand Down
10 changes: 5 additions & 5 deletions src/conference_scheduler/validator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from conference_scheduler import scheduler
from conference_scheduler import converter
from conference_scheduler.lp_problem import constraints


Expand Down Expand Up @@ -75,7 +75,7 @@ def is_valid_solution(solution, events, slots):
"""
if len(solution) == 0:
return False
array = scheduler.solution_to_array(solution, events, slots)
array = converter.solution_to_array(solution, events, slots)
return is_valid_array(array, events, slots)


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


Expand All @@ -121,7 +121,7 @@ def is_valid_schedule(schedule, events, slots):
"""
if len(schedule) == 0:
return False
array = scheduler.schedule_to_array(schedule, events, slots)
array = converter.schedule_to_array(schedule, events, slots)
return is_valid_array(array, events, slots)


Expand All @@ -143,5 +143,5 @@ def schedule_violations(schedule, events, slots):
of a list of strings indicating the nature of the violated
constraints
"""
array = scheduler.schedule_to_array(schedule, events, slots)
array = converter.schedule_to_array(schedule, events, slots)
return array_violations(array, events, slots)
2 changes: 1 addition & 1 deletion tests/lp_problem/test_objective_functions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
from conference_scheduler.lp_problem import objective_functions as of
from conference_scheduler.scheduler import array_to_schedule
from conference_scheduler.converter import array_to_schedule


def test_capacity_demand_difference(slots, events, X):
Expand Down
28 changes: 28 additions & 0 deletions tests/test_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import numpy as np
from conference_scheduler import converter


def test_solution_to_array(valid_solution, valid_array, events, slots):
array = converter.solution_to_array(valid_solution, events, slots)
assert np.array_equal(array, valid_array)
assert all([isinstance(x, np.int8) for x in array.flat])


def test_solution_to_schedule(valid_solution, valid_schedule, events, slots):
schedule = converter.solution_to_schedule(valid_solution, events, slots)
assert type(schedule) is list
assert list(schedule) == valid_schedule


def test_schedule_to_array(valid_schedule, valid_array, events, slots):
array = converter.schedule_to_array(valid_schedule, events, slots)
assert np.array_equal(array, valid_array)
assert all([isinstance(x, np.int8) for x in array.flat])


def test_array_to_schedule(valid_schedule, valid_array, events, slots):
schedule = list(
converter.array_to_schedule(valid_array, events, slots)
)
assert type(schedule) is list
assert schedule == valid_schedule