Skip to content

Commit

Permalink
Merge pull request #18 from rodrigo-arenas/develop
Browse files Browse the repository at this point in the history
0.2.2
  • Loading branch information
rodrigo-arenas authored Mar 19, 2021
2 parents 58bf136 + 87b187f commit ddfbac7
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 26 deletions.
38 changes: 38 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]

**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
20 changes: 20 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ python:
- 3.7
- 3.8
- 3.9
os:
- linux
before_install:
- python --version
- pip install -U pip
install:
- pip install -r dev-requirements.txt
script:
- pytest pyworkforce/ --verbose --color=yes --assert=plain --cov-config=.coveragerc --cov=./
- pytest pyworkforce/ --verbose --color=yes --assert=plain --cov-fail-under=95 --cov-config=.coveragerc --cov=./
after_success:
- codecov
44 changes: 29 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@

[![Build Status](https://www.travis-ci.com/rodrigo-arenas/pyworkforce.svg?branch=main)](https://www.travis-ci.com/rodrigo-arenas/pyworkforce)
[![Codecov](https://codecov.io/gh/rodrigo-arenas/pyworkforce/branch/main/graphs/badge.svg?branch=main&service=github)](https://codecov.io/github/rodrigo-arenas/pyworkforce?branch=main)
[![PyPI Version](https://badge.fury.io/py/pyworkforce.svg)](https://badge.fury.io/py/pyworkforce)
[![Python Version](https://img.shields.io/badge/python-3.6%20%7C%203.7%20%7C%203.8%20%7C%203.9-blue)](https://www.python.org/downloads/)



# pyworkforce
Common tools for workforce management, schedule and optimization problems built on top of packages like google's ortools
Common tools for workforce management, schedule and optimization problems built on top of packages like google's or-tools
and custom modules

## Features:
pyworkforce currently includes:

[Queue Systems](./pyworkforce/queuing):
- **queing.ErlangC:** Find the number of positions required to attend incoming traffic to a constant rate and infinite queue length and no dropout.

[Shifts](./pyworkforce/shifts):
- **shifts.MinAbsDifference:** Find the number of resources to schedule in a shift, based in the number of required positions per time interval (found for example using [queing.ErlangC](./pyworkforce/queuing/erlang.py)), maximum capacity restrictions and static shifts coverage.<br>
This module finds the "optimal" assignation by minimizing the total absolute differences between required resources per interval, against the scheduled resources found by the solver.


# Usage:
For complete list and details of examples go to the
[examples folder](https://github.com/rodrigo-arenas/pyworkforce/tree/develop/examples)

### Queue systems:
install pyworkforce

It can be used for solving the required number of positions to manage a number of transactions,
under some systems pre-defined parameters and goals.
```
pip install pyworkforce
```

If you are having troubles with or-tools installation, check the [or-tools guide](https://github.com/google/or-tools#installation)

### Queue systems:

#### Example:

Expand All @@ -28,32 +43,29 @@ erlang = ErlangC(transactions=100, asa=20/60, aht=3, interval=30, shrinkage=0.3)

positions_requirements = erlang.required_positions(service_level=0.8, max_occupancy=0.85)
print("positions_requirements: ", positions_requirements)


```
Output:
```
>> positions_requirements: {'raw_positions': 14,
'positions': 20,
'service_level': 0.8883500191794669,
'occupancy': 0.7142857142857143,
'waiting_probability': 0.1741319335950498}
```

### Shifts Design

Find the optimal number of persons to assign to a pre-defined list of shifts, under a requirement of persons per period
of day and capacity restrictions

### Shifts
#### Example:

```python
from pyworkforce.shifts import MinAbsDifference

# Rows are the days, each entry of a row, is an hour of the day (24).
# Rows are the days, each entry of a row, is number of positions required at an hour of the day (24).
required_resources = [
[9, 11, 17, 9, 7, 12, 5, 11, 8, 9, 18, 17, 8, 12, 16, 8, 7, 12, 11, 10, 13, 19, 16, 7],
[13, 13, 12, 15, 18, 20, 13, 16, 17, 8, 13, 11, 6, 19, 11, 20, 19, 17, 10, 13, 14, 23, 16, 8]
]

# Each entry of a shift, is an hour of the day (24)
# Each entry of a shift,an hour of the day (24), 1 if the shift covers that hour, 0 otherwise
shifts_coverage = {"Morning": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Afternoon": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
"Night": [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
Expand All @@ -69,7 +81,9 @@ scheduler = MinAbsDifference(num_days=2,

solution = scheduler.solve()
print("solution :", solution)

```
Output:
```
>> solution: {'status': 'OPTIMAL',
'cost': 157.0,
'resources_shifts': [{'day': 0, 'shift': 'Morning', 'resources': 8},
Expand Down
10 changes: 4 additions & 6 deletions pyworkforce/shifts/shifts_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@ def __init__(self, num_days: int,
Solves the following schedule problem:
Its required to find the optimal number of resources (agents, operators, doctors, etc) to allocate
in a shift, based on a pre-defined requirement of # of resources per period of the day (periods of hours,
in a shift, based on a pre-defined requirement of number of resources per period of the day (periods of hours,
half-hour, etc)
The optimal criteria, is defined as the amount of resources per shifts that minimize the total absolute
The "optimal" criteria, is defined as the amount of resources per shifts that minimize the total absolute
difference, between the required resources per period and the actual shifted by the solver
:param num_days: Number of days needed to schedule
:param periods: Number of working periods in a day
:param shifts_coverage: dict with structure {"shift_name": "shift_array"} where "shift_array" is an array
of size [periods] (p), 1 if shift covers period p, 0 otherwise
:param shifts_coverage: dict with structure {"shift_name": "shift_array"} where "shift_array" is an array of size [periods] (p), 1 if shift covers period p, 0 otherwise
:param max_period_concurrency: Maximum resources allowed to shift in any period and day
:param required_resources: Array of size [days, periods]
:param max_shift_concurrency: Number of maximum allowed resources in a same shift
Expand All @@ -52,9 +51,9 @@ def __init__(self, num_days: int,
self.required_resources = required_resources
self.max_search_time = max_search_time
self.num_search_workers = num_search_workers
self.solver = cp_model.CpSolver()
self.transposed_shifts_coverage = None
self.status = None
self.solver = None

def solve(self):
sch_model = cp_model.CpModel()
Expand Down Expand Up @@ -100,7 +99,6 @@ def solve(self):
sch_model.Minimize(
sum(transition_resources[d][p] for d in range(self.num_days) for p in range(self.num_periods)))

self.solver = cp_model.CpSolver()
self.solver.parameters.max_time_in_seconds = self.max_search_time
self.solver.num_search_workers = self.num_search_workers

Expand Down
5 changes: 1 addition & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@

# twine upload --skip-existing --repository-url https://test.pypi.org/legacy/ dist/*

# The directory containing this file
HERE = pathlib.Path(__file__).parent

# The text of the README file
README = (HERE / "README.md").read_text()

# This call to setup() does all the work
setup(
name="pyworkforce",
version="0.2.1",
version="0.2.2",
description="Common tools for workforce management, schedule and optimization problems",
long_description=README,
long_description_content_type="text/markdown",
Expand Down

0 comments on commit ddfbac7

Please sign in to comment.