Skip to content

Commit

Permalink
v1.0.0: add phitter simulation module, merge branch 'development-simu…
Browse files Browse the repository at this point in the history
…lation'
  • Loading branch information
sebastianherreramonterrosa committed Oct 29, 2024
2 parents c767ccf + 667bd1f commit c19f4e6
Show file tree
Hide file tree
Showing 19 changed files with 5,245 additions and 84 deletions.
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2024 Sebastián José Herrera Monterrosa
Copyright (c) 2024 Sebastián José Herrera Monterrosa, Carlos Andrés Másmela Pinilla

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE.
409 changes: 332 additions & 77 deletions README.md

Large diffs are not rendered by default.

408 changes: 408 additions & 0 deletions documentation/FIT.md

Large diffs are not rendered by default.

211 changes: 211 additions & 0 deletions documentation/SIMULATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
# Simulation

## Process Simulation

This will help you to understand your processes. To use it, run the following line

```python
from phitter import simulation

# Create a simulation process instance
simulation = simulation.ProcessSimulation()

```

### Add processes to your simulation instance

There are two ways to add processes to your simulation instance:

- Adding a **process _without_ preceding process (new branch)**
- Adding a **process _with_ preceding process (with previous ids)**

#### Process _without_ preceding process (new branch)

```python
# Add a new process without preceding process
simulation.add_process(
prob_distribution="normal",
parameters={"mu": 5, "sigma": 2},
process_id="first_process",
number_of_products=10,
number_of_servers=3,
new_branch=True,
)

```

#### Process _with_ preceding process (with previous ids)

```python
# Add a new process with preceding process
simulation.add_process(
prob_distribution="exponential",
parameters={"lambda": 4},
process_id="second_process",
previous_ids=["first_process"],
)

```

#### All together and adding some new process

The order in which you add each process **_matters_**. You can add as many processes as you need.

```python
# Add a new process without preceding process
simulation.add_process(
prob_distribution="normal",
parameters={"mu": 5, "sigma": 2},
process_id="first_process",
number_of_products=10,
number_of_servers=3,
new_branch=True,
)

# Add a new process with preceding process
simulation.add_process(
prob_distribution="exponential",
parameters={"lambda": 4},
process_id="second_process",
previous_ids=["first_process"],
)

# Add a new process with preceding process
simulation.add_process(
prob_distribution="gamma",
parameters={"alpha": 15, "beta": 3},
process_id="third_process",
previous_ids=["first_process"],
)

# Add a new process without preceding process
simulation.add_process(
prob_distribution="exponential",
parameters={"lambda": 4.3},
process_id="fourth_process",
new_branch=True,
)


# Add a new process with preceding process
simulation.add_process(
prob_distribution="beta",
parameters={"alpha": 1, "beta": 1, "A": 2, "B": 3},
process_id="fifth_process",
previous_ids=["second_process", "fourth_process"],
)

# Add a new process with preceding process
simulation.add_process(
prob_distribution="normal",
parameters={"mu": 15, "sigma": 2},
process_id="sixth_process",
previous_ids=["third_process", "fifth_process"],
)
```

### Visualize your processes

You can visualize your processes to see if what you're trying to simulate is your actual process.

```python
# Graph your process
simulation.process_graph()
```

![Simulation](./multimedia/simulation_process_graph.png)

### Start Simulation

You can simulate and have different simulation time values or you can create a confidence interval for your process

#### Run Simulation

Simulate several scenarios of your complete process

```python
# Run Simulation
simulation.run(number_of_simulations=100)

# After run
simulation: pandas.Dataframe
```

### Review Simulation Metrics by Stage

If you want to review average time and standard deviation by stage run this line of code

```python
# Review simulation metrics
simulation.simulation_metrics() -> pandas.Dataframe
```

#### Run confidence interval

If you want to have a confidence interval for the simulation metrics, run the following line of code

```python
# Confidence interval for Simulation metrics
simulation.run_confidence_interval(
confidence_level=0.99,
number_of_simulations=100,
replications=10,
) -> pandas.Dataframe
```

## Queue Simulation

If you need to simulate queues run the following code:

```python
from phitter import simulation

# Create a simulation process instance
simulation = simulation.QueueingSimulation(
a="exponential",
a_paramters={"lambda": 5},
s="exponential",
s_parameters={"lambda": 20},
c=3,
)
```

In this case we are going to simulate **a** (arrivals) with _exponential distribution_ and **s** (service) as _exponential distribution_ with **c** equals to 3 different servers.

By default Maximum Capacity **k** is _infinity_, total population **n** is _infinity_ and the queue discipline **d** is _FIFO_. As we are not selecting **d** equals to "PBS" we don't have any information to add for **pbs_distribution** nor **pbs_parameters**

### Run the simulation

If you want to have the simulation results

```python
# Run simulation
simulation = simulation.run(simulation_time = 2000)
simulation: pandas.Dataframe
```

If you want to see some metrics and probabilities from this simulation you should use::

```python
# Calculate metrics
simulation.metrics_summary() -> pandas.Dataframe

# Calculate probabilities
number_probability_summary() -> pandas.Dataframe
```

### Run Confidence Interval for metrics and probabilities

If you want to have a confidence interval for your metrics and probabilities you should run the following line

```python
# Calculate confidence interval for metrics and probabilities
probabilities, metrics = simulation.confidence_interval_metrics(
simulation_time=2000,
confidence_level=0.99,
replications=10,
)

probabilities -> pandas.Dataframe
metrics -> pandas.Dataframe
```
Binary file added multimedia/simulation_process_graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion phitter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
__version__ = "0.7.2"
__version__ = "1.0.0"

from .main import PHITTER
from phitter import continuous
from phitter import discrete
from phitter import simulation
3 changes: 3 additions & 0 deletions phitter/simulation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from phitter.simulation.own_distribution import OwnDistributions
from phitter.simulation.process_simulation import ProcessSimulation
from phitter.simulation.queueing_simulation import QueueingSimulation
1 change: 1 addition & 0 deletions phitter/simulation/own_distribution/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .own_distribution import OwnDistributions
79 changes: 79 additions & 0 deletions phitter/simulation/own_distribution/own_distribution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import random

import numpy as np


class OwnDistributions:
def __init__(self, parameters: dict):
"""Creates the "OwnDistributions" Class
Args:
parameters (dict): Parameters of that distribution. all keys should be numbers greater or equals than zero. All values must sum up to 1.
"""
self.__parameters = parameters

self.__first_verification()

self.__acummulative_parameters = dict()
acum = 0
for key in self.__parameters.keys():
acum += self.__parameters[key]
self.__acummulative_parameters[key] = acum

self.__error_detections()

def __first_verification(self) -> None:
"""Verify if the keys are integers greater than zero, and verify if all values are floats."""
# Quick verification
if isinstance(self.__parameters, dict) == False:
raise ValueError("You must pass a dictionary")

for key in self.__parameters.keys():
if isinstance(key, int) == False:
raise ValueError(
f"""All keys must be integers greater or equal than 0."""
)
elif key < 0:
raise ValueError(
f"""All keys must be integers greater or equal than 0."""
)

if isinstance(self.__parameters[key], float) == False:
raise ValueError(f"""All keys must be floats.""")

def __error_detections(self) -> None:
"""Identify the values that are greater than 1 or less than 0. Verify if accumulative probabilities are less or greater than 1. Must sum 1"""

for key in self.__parameters.keys():
if self.__parameters[key] <= 0 or self.__parameters[key] >= 1:
raise ValueError(
f"""All probabilities must be greater than 0 and less than 1. You have a value of {self.__parameters[key]} for key {key}"""
)

if (
self.__acummulative_parameters[key] > 1
or self.__acummulative_parameters[key] <= 0
):
raise ValueError(
f"""All probabilities must be add up to 1 and must be greater than 0. You have a acummulative value of {self.__acummulative_parameters[key]}"""
)
else:
last = self.__acummulative_parameters[key]

if last != 1:
raise ValueError(
f"""All probabilities must be add up to 1, your probabilities sum a total of {last}"""
)

def ppf(self, probability: int) -> int:
"""Assign a label according to a probability given by the created distribution
Args:
probability (int): Number between 0 and 1
Returns:
int: Returns label according to probability
"""
for label in self.__acummulative_parameters.keys():
if probability <= self.__acummulative_parameters[label]:
return label
1 change: 1 addition & 0 deletions phitter/simulation/process_simulation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .process_simulation import ProcessSimulation
Loading

0 comments on commit c19f4e6

Please sign in to comment.