Skip to content

Commit

Permalink
Copy editing for matching, regression, workforce (#105)
Browse files Browse the repository at this point in the history
* Copy editing

* more fixes

* more fixes
  • Loading branch information
simonbowly authored Jun 26, 2023
1 parent 911a9b1 commit 04c5944
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 47 deletions.
49 changes: 25 additions & 24 deletions docs/source/mods/bipartite-matching.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ Maximum Bipartite Matching
==========================

The maximum matching problem is a fundamental problem in graph theory. Given
a graph, as a set of nodes connected to one another by edges, a matching
a graph as a set of nodes connected by edges, a matching
is any subset of those edges that have no vertex in common. The goal of
maximum matching is to find the largest possible such matching in a given
maximum matching is to find the largest possible matching in a given
graph.

In this Mod we consider the special case of maximum cardinality matching on
bipartite graphs, which can be used to solve exclusive assignment
problems such as the assignment of workers or resources to tasks.
To give a brief example, if we construct a bipartite graph where one of the
bipartite sets represents tasks, and the other workers, then a matching is a
set of edges each of which assigns one worker to one task. By the properties
of a matching, each worker is assigned at most one task and each task is
completed by at most one worker. The maximum cardinality matching is one that
maximises the number of completed tasks (and workers given work).
bipartite graphs. This theoretical problem can be used to solve practical
problems such as the assignment of workers or resources to tasks. We
construct a bipartite graph where one of the bipartite sets represents tasks,
the other represents workers, and an edge exists between a given worker and task
if the worker may complete that task. A matching then defines an allocation of
workers to tasks, such that each worker is allocated to at most
one task and each task is designated to be completed by at most one worker. The
maximum cardinality matching maximizes the number of completed tasks and,
consequently, the number of workers who are given work.

.. Figure generated using networkx, see bipartite-matching-figs.py
.. figure:: figures/bipartite-matching-example.png
Expand All @@ -29,8 +30,8 @@ Problem Specification

Consider a bipartite graph :math:`G(U, V, E)`, where :math:`U` and :math:`V`
are disjoint vertex sets, and the edge set :math:`E \subseteq U \times V`
connects vertices between, not within, the sets. A matching on this graph is any
subset of edges such that no vertex is incident to more than one edge.
connects vertices between, but not within, the sets. A matching on this graph
is any subset of edges such that no vertex is incident to more than one edge.
Equivalently, a matching is a subgraph of :math:`G` where all vertices
have degree at most one. A maximum matching is the largest possible matching
on :math:`G`.
Expand All @@ -41,10 +42,10 @@ on :math:`G`.
the problem to a minimum-cost flow problem. To do so, we introduce a source
vertex as a predecessor to all vertices in :math:`U`, and a sink vertex as a
successor to all vertices in :math:`V`. Giving every edge unit capacity, a
maximum matching is found by maximizing flow from the source to the sink. As
a min-cost flow, this is equivalent to adding an edge with a negative cost
from the sink to the source and assigning zero cost to all other edges. All
edges with non-zero flow in the min-cost flow solution are part of the
maximum matching is found by maximizing flow from the source to the sink. To
create a minimum-cost flow formulation, an edge with negative cost is added
from the sink and the source. All other edges are assigned zero cost. All
edges with non-zero flow in the minimum-cost flow solution are part of the
matching.

.. Figure generated using networkx, see bipartite-matching-figs.py
Expand All @@ -54,17 +55,18 @@ on :math:`G`.

A maximum flow network for the bipartite matching problem

We do not describe the mathematical formulation here, see :doc:`/mods/min-cost-flow`
for details. The important point to note is that when this continuous model is
solved using the simplex algorithm, we are guaranteed to get an integral solution
and thus the solution can be used to select a set of edges for the matching.
We do not describe the mathematical formulation here; for further details
refer to the :doc:`/mods/min-cost-flow` Mod. The important point to note
is that solving this continuous model with the simplex algorithm guarantees
an integral solution which can therefore be used to select a set of edges
for the matching.

Interface
---------

The ``maximum_bipartite_matching`` function supports scipy sparse arrays, pandas
dataframes, and networkx graphs as possible inputs. The user must also provide
the bipartite partitioning of the input graph. In all cases, the matching is
the bipartite partitions of the input graph. In all cases, the matching is
returned as a sub-graph of the input data structure.

.. tabs::
Expand Down Expand Up @@ -162,9 +164,8 @@ returned as a sub-graph of the input data structure.


The ``maximum_bipartite_matching`` function formulates a linear program for the
the network flow model corresponding to the given bipartite graph. Since the
model is formulated as a network flow, Gurobi will in most cases solve the model
using a network primal simplex algorithm.
the minimum-cost network flow problem corresponding to the given bipartite graph.
Gurobi will in most cases solve the model using a network primal simplex algorithm.

Solution
--------
Expand Down
16 changes: 8 additions & 8 deletions docs/source/mods/lad-regression.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ Least Absolute Deviation Regression

Least Absolute Deviation (LAD) regression is an alternative to the more commonly
used Ordinary Least Squares (OLS) regression method. The distinction between the
two comes down to the error metrics they use when fitted to training data: LAD
two is the error metric used to fit the predictive model to training data. LAD
minimizes the sum of absolute residuals, while OLS minimizes the sum of
squares of residuals.

Though most machine learning practitioners are probably more familiar with OLS,
LAD was proposed around 50 years earlier :footcite:p:`birkes2011alternative`.
OLS gained more popularity partly due to the fact that the computations required
were simpler. In fact, it was the development of linear programming that made
were simpler. It was the development of linear programming that made
LAD computationally manageable :footcite:p:`bloomfield1980least`.

LAD is generally more robust than OLS in that it is more resistant to outliers
in the response variable :footcite:p:`birkes2011alternative`. A large residual
for a single data point is amplified in its contribution to the loss function in
OLS, since the residuals are squared. As a result, a single outlier can have a
LAD is more robust than OLS in that it is more resistant to outliers
in the response variable :footcite:p:`birkes2011alternative`. In OLS, a large residual
for a single data point makes an outsized contribution to the loss function
since the residuals are squared. As a result, a single outlier can have a
large effect on the fitted coefficients and skew the resulting model. By
contrast, a large deviation in an individual point has a less extreme effect on
the linear loss function of LAD.
Expand All @@ -26,7 +26,7 @@ Problem Specification

Scikit-learn's documentation gives a general explanation of `Linear Models
<https://scikit-learn.org/stable/modules/linear_model.html>`_. The distinction
between this Mod and the Ordinary Least Squares regression from scikit-learn is the
between this Mod and the Ordinary Least Squares regression algorithm from scikit-learn is the
loss function. ``LADRegression`` chooses coefficients :math:`w` of a linear model
:math:`y = Xw` so as to minimize the sum of absolute errors on a training
dataset :math:`(X, y)`. In other words, it aims to minimize the
Expand Down Expand Up @@ -130,7 +130,7 @@ coefficients found using Ordinary Least Squares (OLS).
plt.figure(figsize=(8, 4))
coefficients.plot.bar(ax=plt.gca())

At this stage there isn't much to observe; the chosen coefficients are broadly
At this stage there isn't much to observe; the chosen coefficients are
similar:

.. figure:: figures/lad-regression-coeffs.png
Expand Down
30 changes: 15 additions & 15 deletions docs/source/mods/workforce.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ Workforce Scheduling

Workforce scheduling is an extremely widely-used application of optimization in
practice. It involves balancing many competing concerns such as worker
availability, cost, and preferences, shift coverage requirements, conditions on
consecutive shifts or rest breaks, etc. Implementation can become quite
availability, cost, and preferences; shift coverage requirements; conditions on
consecutive shifts and rest breaks; and so on. Implementation can become quite
involved as worker requirements and entitlements become more complex.

This Mod implements several basic variants of workforce scheduling. The initial
Expand All @@ -17,7 +17,7 @@ Problem Specification

This first example covers a simple case for a business developing a two-week
roster. Each shift requires a given number of workers who have identical skills
and productivity. In other words, any work can cover any shift, and all workers
and productivity. In other words, any worker can cover any shift, and all workers
are considered equivalent. Workers provide their availability for shifts.
Rest requirements and minimum work entitlements are handled through upper and
lower limits, respectively, on the number of shifts a worker is rostered on
Expand All @@ -41,15 +41,15 @@ The workforce scheduling Mod takes the following three pandas dataframes as inpu
number of shifts the given worker may be assigned in the schedule. There
must be one row for every unique worker mentioned in ``availability["Worker"]``.

When ``solve_workforce_scheduling`` is called, a model is formulated and solved
immediately using Gurobi. Workers will be assigned only to shifts they are
When the main function ``solve_workforce_scheduling`` is called, a model is formulated
and solved using Gurobi. Workers will be assigned only to shifts they are
available for, in such a way that all requirements are covered, minimum and
maximum shift numbers are respected, and the total sum of worker preference
scores is maximised. If ``preferences=None``, preferences are not considered and any
scores is maximized. If ``preferences=None``, preferences are not considered and any
feasible schedule will be returned.

The returned assignment dataframe is a subset of the availability dataframe,
with the same columns. A row in the returned dataframe specifies that the given
The returned assignment dataframe is a subset of the rows of the availability
dataframe. The presence of a row in the returned dataframe signifies that the given
worker has been assigned to the given shift.

.. dropdown:: Background: Mathematical Model
Expand All @@ -60,7 +60,7 @@ worker has been assigned to the given shift.
assigned shift. Shift :math:`s` requires :math:`r_{s}` workers assigned.
Each worker must be assigned between :math:`l_{w}` and :math:`u_{w}`
shifts in total. The model is defined on binary variables :math:`x_{ws}`
that satisfy the condition
that represent shift assignments as follows:

.. math::
Expand All @@ -80,7 +80,7 @@ worker has been assigned to the given shift.
& x_{ws} \in \lbrace 0, 1 \rbrace & \forall s \in S, w \in W_{s} \\
\end{alignat}
The objective computes the total preference of all shift assignments, which
The objective computes the total preference value of all shift assignments, which
we seek to maximize. The first constraint ensures that all shifts are
assigned the required number of workers, while the second constraint
ensures workers are assigned to an acceptable number of shifts.
Expand Down Expand Up @@ -188,7 +188,7 @@ below show example data for each frame.
and :math:`u_w`.

The example code below solves the workforce scheduling problem for the above
dataset. The dataset can be imported from the ``gurobi-optimods.datasets`` module.
dataset. The dataset is imported from the ``gurobi-optimods.datasets`` module.

.. testcode:: workforce

Expand Down Expand Up @@ -350,16 +350,16 @@ set to ``True`` to enforce the new requirement.
2023-05-13 Y Y Y Y Y Y Y
2023-05-14 - Y Y Y Y Y -

Notice that Siva's shifts have been adjusted so as to avoid any worker working
more than five consecutive days.
Notice that Siva's shifts have been adjusted to meet the requirement that
not worker should work five or more consecutive days.

Further Requirements
--------------------

As mentioned in the introduction, this Mod implements some basic cases of
workforce scheduling, and is limited in scope. However, similar modelling
approaches to those described here can be applied to handle more complex
requirements. For further information, see :footcite:t:`ERNST20043` (among many,
many other references on the topic).
requirements. For further information, see :footcite:t:`ERNST20043` (one
among many references on the topic).

.. footbibliography::

0 comments on commit 04c5944

Please sign in to comment.