Merge branch 'latex'
This commit is contained in:
commit
7c1e115951
19 changed files with 935 additions and 0 deletions
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
*.aux
|
||||
*.log
|
||||
*.swp
|
||||
*.out
|
||||
*.pdf
|
||||
*.toc
|
||||
*.maf
|
||||
*.mtc
|
||||
*.mtc0
|
||||
*.stc
|
||||
*.stc0
|
||||
*.stc1
|
||||
*.stc2
|
||||
*.stc3
|
||||
*.bbl
|
||||
*.blg
|
||||
*.stc*
|
||||
*.bcf
|
||||
*.run.xml
|
||||
|
||||
|
|
@ -29,3 +29,10 @@ Oral: 15 min de présentation - 5 min de questions
|
|||
|
||||
trouver un argument solide sur pk on a choisi ce projet
|
||||
|
||||
## Compiling report
|
||||
|
||||
Install the necessary tools with `sudo apt-get install texlive-full`.
|
||||
|
||||
Navigate to `latex` directory and then run `pdflatex main.tex`. The output pdf
|
||||
should be at `main.pdf`. You may want to run `biber main` first, to compile the
|
||||
bibliography.
|
||||
|
|
41
complexity-analysis/direct.py
Normal file
41
complexity-analysis/direct.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
# importing the memory tracking module
|
||||
import tracemalloc
|
||||
from random import random
|
||||
from math import floor, sqrt
|
||||
#from statistics import mean, variance
|
||||
from time import perf_counter
|
||||
|
||||
# starting the monitoring
|
||||
tracemalloc.start()
|
||||
|
||||
start_time = perf_counter()
|
||||
|
||||
# store memory consumption before
|
||||
current_before, peak_before = tracemalloc.get_traced_memory()
|
||||
|
||||
N = 10**6
|
||||
Tot = 0
|
||||
Tot2 = 0
|
||||
for _ in range(N):
|
||||
item = random()
|
||||
Tot += item
|
||||
Tot2 += item ** 2
|
||||
mean = Tot / N
|
||||
variance = Tot2 / (N-1) - mean**2
|
||||
|
||||
# store memory after
|
||||
current_after, peak_after = tracemalloc.get_traced_memory()
|
||||
|
||||
end_time = perf_counter()
|
||||
|
||||
print("mean :", mean)
|
||||
print("variance :", variance)
|
||||
|
||||
# displaying the memory usage
|
||||
print("Used memory before : {} B (current), {} B (peak)".format(current_before,peak_before))
|
||||
print("Used memory after : {} B (current), {} B (peak)".format(current_after,peak_after))
|
||||
print("Used memory : {} B".format(peak_after - current_before))
|
||||
print("Time : {} ms".format((end_time - start_time) * 1000))
|
||||
|
||||
# stopping the library
|
||||
tracemalloc.stop()
|
36
complexity-analysis/using_libs.py
Normal file
36
complexity-analysis/using_libs.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# importing the memory tracking module
|
||||
import tracemalloc
|
||||
from random import random
|
||||
from math import floor, sqrt
|
||||
from statistics import mean, variance
|
||||
from time import perf_counter
|
||||
|
||||
# starting the monitoring
|
||||
tracemalloc.start()
|
||||
|
||||
start_time = perf_counter()
|
||||
|
||||
# store memory consumption before
|
||||
current_before, peak_before = tracemalloc.get_traced_memory()
|
||||
|
||||
N = 10**6
|
||||
values = [random() for _ in range(N)]
|
||||
mean = mean(values)
|
||||
variance = variance(values)
|
||||
|
||||
# store memory after
|
||||
current_after, peak_after = tracemalloc.get_traced_memory()
|
||||
|
||||
end_time = perf_counter()
|
||||
|
||||
print("mean :", mean)
|
||||
print("variance :", variance)
|
||||
|
||||
# displaying the memory usage
|
||||
print("Used memory before : {} B (current), {} B (peak)".format(current_before,peak_before))
|
||||
print("Used memory after : {} B (current), {} B (peak)".format(current_after,peak_after))
|
||||
print("Used memory : {} B".format(peak_after - current_before))
|
||||
print("Time : {} ms".format((end_time - start_time) * 1000))
|
||||
|
||||
# stopping the library
|
||||
tracemalloc.stop()
|
42
latex/advanced.params/misc.commands.tex
Normal file
42
latex/advanced.params/misc.commands.tex
Normal file
|
@ -0,0 +1,42 @@
|
|||
\newcommand\tab[1][0.6cm]{\hspace*{#1}} %Create and define tab
|
||||
|
||||
\definecolor{lightgray}{gray}{0.85}
|
||||
\definecolor{lightgrey}{gray}{0.85}
|
||||
\definecolor{vlg}{gray}{0.85}
|
||||
|
||||
|
||||
%Patch pour utiliser des équations dans les titres sans que hypperref nous insulte.
|
||||
% Définition cyclique, compile pas. Mais c'est l"idée
|
||||
%\renewcommand{\chapter}[1]{\chapter{\texorpdfstring{#1}}}
|
||||
%\renewcommand{\section}[1]{\section{\texorpdfstring{#1}}}
|
||||
%\renewcommand{\subsection}[1]{\subsection{\texorpdfstring{#1}}}
|
||||
%\renewcommand{\subsubsection}[1]{\subsubsection{\texorpdfstring{#1}}}
|
||||
|
||||
%Chapter No Numbering but appears in TOC
|
||||
\newcommand{\chapternn}[1]{\chapter*{#1}\addcontentsline{toc}{chapter}{#1}}
|
||||
\newcommand{\sectionnn}[1]{\phantomsection\section*{#1}\addcontentsline{toc}{section}{#1}}
|
||||
% phantomsection is necessary for links in TOC to function. It places the anchor
|
||||
\newcommand{\subsectionnn}[1]{\subsection*{#1}\addcontentsline{toc}{subsection}{#1}}
|
||||
\newcommand{\subsubsectionnn}[1]{\subsubsection*{#1}\addcontentsline{toc}{subsubsection}{#1}}
|
||||
|
||||
\newcolumntype{L}[1]{>{\raggedright\arraybackslash\hspace{0pt}}p{#1}}
|
||||
\newcolumntype{R}[1]{>{\raggedleft\arraybackslash\hspace{0pt}}p{#1}}
|
||||
\newcolumntype{C}[1]{>{\centering\arraybackslash\hspace{0pt}}p{#1}}
|
||||
|
||||
|
||||
\renewcommand\thesection{\arabic{section}}
|
||||
\renewcommand\thesubsection{\thesection.\arabic{subsection}}
|
||||
|
||||
%------- Do not append new commands after :
|
||||
|
||||
\hypersetup{
|
||||
colorlinks=false, % colorise les liens
|
||||
linkbordercolor={1 1 1},
|
||||
breaklinks=true, % permet le retour à la ligne dans les liens trop longs
|
||||
urlcolor=blue, % couleur des hyperliens
|
||||
linkcolor=black, % couleur des liens internes
|
||||
citecolor=black, % couleur des références
|
||||
pdftitle={}, % informations apparaissant dans
|
||||
pdfauthor={}, % les informations du document
|
||||
pdfsubject={} % sous Acrobat.
|
||||
}
|
13
latex/advanced.params/tikz.conf.tex
Normal file
13
latex/advanced.params/tikz.conf.tex
Normal file
|
@ -0,0 +1,13 @@
|
|||
% \tikzset{every picture/.style={execute at begin picture={
|
||||
% \shorthandoff{:;!?};}
|
||||
% }}
|
||||
|
||||
\tikzset{
|
||||
boxnode/.style={ % requires library shapes.misc
|
||||
draw,
|
||||
rectangle,
|
||||
text centered,
|
||||
align=center,
|
||||
fill=gray!5!white
|
||||
},
|
||||
}
|
57
latex/annex-performance.tex
Normal file
57
latex/annex-performance.tex
Normal file
|
@ -0,0 +1,57 @@
|
|||
For simplicity, we only include the script for the improved algorithm. For the
|
||||
intuitive algorithm, simply replace the algorithm. The imports, timing and memory
|
||||
usage tracking code are nearly identical.
|
||||
|
||||
\begin{lstlisting}[language=python]
|
||||
#!/usr/bin/python3
|
||||
import tracemalloc
|
||||
from random import random
|
||||
from math import floor, sqrt
|
||||
#from statistics import mean, variance
|
||||
from time import perf_counter
|
||||
|
||||
# starting the memory monitoring
|
||||
tracemalloc.start()
|
||||
|
||||
start_time = perf_counter()
|
||||
|
||||
# store memory consumption before
|
||||
current_before, peak_before = tracemalloc.get_traced_memory()
|
||||
|
||||
# algorithm (part to replace)
|
||||
N = 10**6
|
||||
Tot = 0
|
||||
Tot2 = 0
|
||||
for _ in range(N):
|
||||
item = random()
|
||||
Tot += item
|
||||
Tot2 += item ** 2
|
||||
mean = Tot / N
|
||||
variance = Tot2 / (N-1) - mean**2
|
||||
|
||||
# store memory after
|
||||
current_after, peak_after = tracemalloc.get_traced_memory()
|
||||
|
||||
end_time = perf_counter()
|
||||
|
||||
print("mean :", mean)
|
||||
print("variance :", variance)
|
||||
|
||||
# displaying the memory usage
|
||||
print("Used memory before : {} B (current), {} B (peak)".format(current_before,peak_before))
|
||||
print("Used memory after : {} B (current), {} B (peak)".format(current_after,peak_after))
|
||||
print("Used memory : {} B".format(peak_after - current_before))
|
||||
print("Time : {} ms".format((end_time - start_time) * 1000))
|
||||
|
||||
tracemalloc.stop()
|
||||
\end{lstlisting}
|
||||
|
||||
Example output:
|
||||
\begin{lstlisting}[language=python]
|
||||
mean : 0.5002592040785124
|
||||
variance : 0.0833757719902084
|
||||
Used memory before : 0 B (current), 0 B (peak)
|
||||
Used memory after : 1308 B (current), 1336 B (peak)
|
||||
Used memory : 1336 B
|
||||
Time : 535.1873079998768 ms
|
||||
\end{lstlisting}
|
5
latex/annex-probabilistic.tex
Normal file
5
latex/annex-probabilistic.tex
Normal file
|
@ -0,0 +1,5 @@
|
|||
Script should have been provided with report. % TODO
|
||||
|
||||
\lstinputlisting[language=Python]{../Probas.py}
|
||||
|
||||
% TODO include output example
|
18
latex/bibliography.bib
Normal file
18
latex/bibliography.bib
Normal file
|
@ -0,0 +1,18 @@
|
|||
@book{hofri:1987,
|
||||
author = {Hofri, M.},
|
||||
title = {Probabilistic Analysis of Algorithms: On Computing Methodologies for
|
||||
Computer Algorithms Performance Evaluation},
|
||||
year = {1987},
|
||||
isbn = {0387965785},
|
||||
publisher = {Springer-Verlag},
|
||||
address = {Berlin, Heidelberg},
|
||||
}
|
||||
|
||||
@misc{bin-packing-approximation:2022,
|
||||
author = {{Computational Thinking}},
|
||||
title = {Bin Packing Approximation},
|
||||
year = {2022},
|
||||
howpublished = {YouTube video},
|
||||
url = {https://www.youtube.com/watch?v=R76aAh_li50},
|
||||
}
|
||||
|
3
latex/clean.sh
Normal file
3
latex/clean.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
rm main.stc* main.toc main.bcf *.aux *.out main.mtc*
|
||||
rm main.maf main.run.xml
|
||||
rm main.log
|
436
latex/content.tex
Normal file
436
latex/content.tex
Normal file
|
@ -0,0 +1,436 @@
|
|||
\sectionnn{Introduction}
|
||||
|
||||
Bin packing is the process of packing a set of items of different sizes into
|
||||
containers of a fixed capacity in a way that minimizes the number of containers
|
||||
used. This has applications in many fields, such as logistics, where we want to
|
||||
optimize the storage and transport of items in boxes, containers, trucks, etc.
|
||||
|
||||
Building mathematical models for bin packing is useful in understanding the
|
||||
problem and in designing better algorithms, depending on the use case. An
|
||||
algorithm optimized for packing cubes into boxes will not perform as well as
|
||||
another algorithm for packing long items into trucks. Studying the mathematics
|
||||
behind algorithms provides us with a better understanding of what works best.
|
||||
When operating at scale, every small detail can have a huge impact on overall
|
||||
efficiency and cost. Therefore, carefully developing algorithms based on solid
|
||||
mathematical models is crucial. As we have seen in our Automatics class, a
|
||||
small logic breach can be an issue in the long run in systems that are supposed
|
||||
to run autonomously. This situation can be avoided by using mathematical models
|
||||
during the design process wich will lead to better choices welding economic and
|
||||
relibility concerns.
|
||||
|
||||
We will conduct a probabilistic analysis of multiple algorithms and compare
|
||||
results to theoretical values. We will also consider the algoriths complexity
|
||||
and performance, both in resource consumption and in box usage.
|
||||
|
||||
\clearpage
|
||||
|
||||
\section{Bin packing use cases}
|
||||
|
||||
Before studying the mathematics behind bin packing algorithms, we will have a
|
||||
look at the motivations behind this project.
|
||||
|
||||
Bin packing has applications in many fields and allows to automize and optimize
|
||||
complex systems. We will illustrate with examples focusing on two use cases:
|
||||
logistics and computer science. We will consider examples of multiple dimensions
|
||||
to show the versatility of bin packing algorithms.
|
||||
|
||||
\paragraph{} In the modern day, an effective supply chain relies on an automated production
|
||||
thanks to sensors and actuators installed along conveyor belts. It is often
|
||||
required to implement a packing procedure. All of this is controlled by a
|
||||
computer system running continuously.
|
||||
|
||||
\subsection{3D : Containers}
|
||||
|
||||
Storing items in containers can be a prime application of bin packing. These
|
||||
tree-dimensional objects of standardized size are used to transport goods.
|
||||
While the dimensions of the containers are predictable, those of the transported
|
||||
items are not. Storage is furthermore complicated by the fact that there can be
|
||||
a void between items, allowing to move around. Multiple types of items can also
|
||||
be stored in the same container.
|
||||
|
||||
There are many ways to optimize the storage of items in containers. For
|
||||
example, by ensuring items are of an optimal standardized size or by storing a
|
||||
specific item in each container, both eliminating the randomness in item size.
|
||||
In these settings, it is easy to fill a container by assimilating them to
|
||||
rectangular blocks. However, when items come in pseudo-random dimensions, it is
|
||||
intuitive to start filling the container with larger items and then filling the
|
||||
remaining gaps with smaller items. As containers must be closed, in the event
|
||||
of an overflow, the remaining items must be stored in another container.
|
||||
|
||||
\subsection{2D : Cutting stock problem}
|
||||
|
||||
In industries such as woodworking bin packing algorithms are utilized to
|
||||
minimize material waste when cutting large planks into smaller pieces of
|
||||
desired sizes. Many tools use this two-dimensional cut process. For example, at
|
||||
the Fabric'INSA Fablab, the milling machine, laser cutter and many more are
|
||||
used to cut large planks of wood into smaller pieces for student projects. In
|
||||
this scenario, we try to organize the desired cuts in a way that minimizes the
|
||||
unusable excess wood.
|
||||
|
||||
\begin{figure}[ht]
|
||||
\centering
|
||||
\includegraphics[width=0.65\linewidth]{graphics/fraiseuse.jpg}
|
||||
\caption[]{Milling machine at the Fabric'INSA Fablab \footnotemark}
|
||||
\label{fig:fraiseuse}
|
||||
\end{figure}
|
||||
\footnotetext{Photo courtesy of Inés Bafaluy}
|
||||
|
||||
Managing the placement of items of complex shapes can be optimized by using
|
||||
by various algorithms minimizing the waste of material.
|
||||
|
||||
\subsection{1D : Networking}
|
||||
|
||||
When managing network traffic at scale, efficiently routing packets is
|
||||
necessary to avoid congestion, which leads to lower bandwidth and higher
|
||||
latency. Say you're a internet service provider and your users are watching
|
||||
videos on popular streaming platforms. You want to ensure that the traffic is
|
||||
balanced between the different routes to minimize throttling and energy
|
||||
consumption.
|
||||
|
||||
\paragraph{} We can consider the different routes as bins and the users'
|
||||
bandwidth as the items. If a bin overflows, we can redirect the traffic to
|
||||
another route. Using less bins means less energy consumption and decreased
|
||||
operating costs. This is a good example of bin packing in a dynamic
|
||||
environment, where the items are constantly changing. Humans are not involved
|
||||
in the process, as it is fast-paced and requires a high level of automation.
|
||||
|
||||
\vspace{0.4cm}
|
||||
|
||||
\paragraph{} We have seen multiple examples of how bin packing algorithms can
|
||||
be used in various technical fields. In these examples, a choice was made,
|
||||
evaluating the process effectiveness and reliability, based on a probabilistic
|
||||
analysis allowing the adaptation of the algorithm to the use case. We will now
|
||||
conduct our own analysis and study various algorithms and their probabilistic
|
||||
advantages, focusing on one-dimensional bin packing, where we try to store
|
||||
items of different heights in a linear bin.
|
||||
|
||||
\section{Next Fit Bin Packing algorithm (NFBP)}
|
||||
|
||||
Our goal is to study the number of bins $ H_n $ required to store $ n $ items
|
||||
for each algorithm. We first consider the Next Fit Bin Packing algorithm, where
|
||||
we store each item in the current bin if it fits, otherwise we open a new bin.
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering
|
||||
\begin{tikzpicture}[scale=0.8]
|
||||
% Bins
|
||||
\draw[thick] (0,0) rectangle (2,6);
|
||||
\draw[thick] (3,0) rectangle (5,6);
|
||||
\draw[thick] (6,0) rectangle (8,6);
|
||||
|
||||
% Items
|
||||
\draw[fill=red] (0.5,0.5) rectangle (1.5,3.25);
|
||||
\draw[fill=blue] (0.5,3.5) rectangle (1.5,5.5);
|
||||
\draw[fill=green] (3.5,0.5) rectangle (4.5,1.5);
|
||||
\draw[fill=orange] (3.5,1.75) rectangle (4.5,3.75);
|
||||
\draw[fill=purple] (6.5,0.5) rectangle (7.5,2.75);
|
||||
\draw[fill=yellow] (6.5,3) rectangle (7.5,4);
|
||||
|
||||
% arrow
|
||||
\draw[->, thick] (8.6,3.5) -- (7.0,3.5);
|
||||
\draw[->, thick] (8.6,1.725) -- (7.0,1.725);
|
||||
|
||||
% Labels
|
||||
\node at (1,-0.75) {Bin 0};
|
||||
\node at (4,-0.75) {Bin 1};
|
||||
\node at (7,-0.75) {Bin 2};
|
||||
\node at (10.0,3.5) {Yellow item};
|
||||
\node at (10.0,1.725) {Purple item};
|
||||
|
||||
\end{tikzpicture}
|
||||
\label{fig:nfbp}
|
||||
\caption{Next Fit Bin Packing example}
|
||||
\end{figure}
|
||||
|
||||
\paragraph{} The example in figure \ref{fig:nfbp} shows the limitations of the
|
||||
NFBP algorithm. The yellow item is stored in bin 2, while it could fit in bin
|
||||
1, because the purple item is considered first and is too large to fit.
|
||||
|
||||
\paragraph{} Each bin will have a fixed capacity of $ 1 $ and items
|
||||
will be of random sizes between $ 0 $ and $ 1 $.
|
||||
|
||||
\subsection{Variables used in models}
|
||||
|
||||
We use the following variables in our algorithms and models :
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
\item $ U_n $ : the size of the $ n $-th item. $ (U_n)_{n \in \mathbb{N^*}} $
|
||||
denotes the mathematical sequence of random variables of uniform
|
||||
distribution on $ [0, 1] $ representing the items' sizes.
|
||||
|
||||
\item $ T_i $ : the number of items in the $ i $-th bin.
|
||||
|
||||
\item $ V_i $ : the size of the first item in the $ i $-th bin.
|
||||
|
||||
\item $ H_n $ : the number of bins required to store $ n $ items.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
Mathematically, the NFBP algorithm imposes the following constraint on the first box :
|
||||
|
||||
\begin{align*}
|
||||
T_1 = k \iff & U_1 + U_2 + \ldots + U_{k} < 1 \\
|
||||
\text{ and } & U_1 + U_2 + \ldots + U_{k+1} \geq 1 \qquad \text{ with } k \geq 1 \\
|
||||
\end{align*}
|
||||
|
||||
|
||||
\subsection{Implementation and results}
|
||||
|
||||
We implemented the NFBP algorithm in Python \footnotemark, for its ease of use
|
||||
and broad recommendation. We used the \texttt{random} library to generate
|
||||
random numbers between $ 0 $ and $ 1 $ and \texttt{matplotlib} to plot the
|
||||
results in the form of histograms. We ran $ R = 10^6 $ simulations with
|
||||
$ N = 10 $ different items each.
|
||||
|
||||
\footnotetext{The code is available in Annex \ref{annex:probabilistic}}
|
||||
|
||||
\paragraph{Distribution of $ T_i $} We first studied how many items were
|
||||
present per bin.
|
||||
|
||||
\paragraph{Distribution of $ V_i $} We then looked at the size of the first
|
||||
item in each bin.
|
||||
|
||||
\paragraph{Asymptotic behavior of $ H_n $} Finally, we analyzed how many bins
|
||||
were needed to store $ n $ items.
|
||||
|
||||
% TODO histograms
|
||||
% TODO analysis histograms
|
||||
|
||||
|
||||
|
||||
|
||||
\cite{hofri:1987}
|
||||
% TODO mettre de l'Histoire
|
||||
|
||||
\section{Next Fit Dual Bin Packing algorithm (NFDBP)}
|
||||
|
||||
Next Fit Dual Bin Packing is a variation of NFBP in which we allow the bins to
|
||||
overflow. A bin must be fully filled, unless it is the last bin.
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering
|
||||
\begin{tikzpicture}[scale=0.8]
|
||||
% Bins
|
||||
\draw[thick] (0,0) rectangle (2,6);
|
||||
\draw[thick] (3,0) rectangle (5,6);
|
||||
|
||||
% Transparent Tops
|
||||
\fill[white,opacity=1.0] (0,5.9) rectangle (2,6.5);
|
||||
\fill[white,opacity=1.0] (3,5.9) rectangle (5,6.5);
|
||||
|
||||
% Items
|
||||
\draw[fill=red] (0.5,0.5) rectangle (1.5,3.25);
|
||||
\draw[fill=blue] (0.5,3.5) rectangle (1.5,5.5);
|
||||
\draw[fill=green] (0.5,5.75) rectangle (1.5,6.75);
|
||||
\draw[fill=orange] (3.5,0.5) rectangle (4.5,2.5);
|
||||
\draw[fill=purple] (3.5,2.75) rectangle (4.5,5.0);
|
||||
\draw[fill=yellow] (3.5,5.25) rectangle (4.5,6.25);
|
||||
|
||||
% Labels
|
||||
\node at (1,-0.75) {Bin 0};
|
||||
\node at (4,-0.75) {Bin 1};
|
||||
|
||||
\end{tikzpicture}
|
||||
\caption{Next Fit Dual Bin Packing example}
|
||||
\label{fig:nfdbp}
|
||||
\end{figure}
|
||||
|
||||
\paragraph{} The example in figure \ref{fig:nfdbp} shows how NFDBP utilizes
|
||||
less bins than NFBP, due to less stringent constraints. The top of the bin is
|
||||
effectively removed, allowing for an extra item to be stored in the bin. We can
|
||||
easily see how with NFDBP each bin can at least contain two items.
|
||||
|
||||
\paragraph{} The variables used are the same as for NFBP. Mathematically, the
|
||||
new constraints on the first bin can be expressed as follows :
|
||||
|
||||
\begin{align*}
|
||||
T_1 = k \iff & U_1 + U_2 + \ldots + U_{k-1} < 1 \\
|
||||
\text{ and } & U_1 + U_2 + \ldots + U_{k} \geq 1 \qquad \text{ with } k \geq 2 \\
|
||||
\end{align*}
|
||||
|
||||
\subsection{La giga demo}
|
||||
|
||||
Let $ k \in \mathbb{N} $. Let $ (U_n)_{n \in \mathbb{N}} $ be a sequence of
|
||||
independent random variables with uniform distribution on $ [0, 1] $, representing
|
||||
the size of the $ n $-th item.
|
||||
|
||||
Let $ i \in \mathbb{N} $. $ T_i $ denotes the number of items in the $ i $-th
|
||||
bin. We have that
|
||||
|
||||
\begin{equation}
|
||||
T_i = k \iff U_1 + U_2 + \ldots + U_{k-1} < 1 \text{ and } U_1 + U_2 + \ldots + U_{k} \geq 1
|
||||
\end{equation}
|
||||
|
||||
Let $ A_k = \{ U_1 + U_2 + \ldots + U_{k-1} < 1 \}$. Hence,
|
||||
|
||||
\begin{align*}
|
||||
% TODO = k
|
||||
P(T_i = k)
|
||||
& = P(A_{k-1} \cap A_k^c) \\
|
||||
& = P(A_{k-1}) - P(A_k) \qquad \text{ (as $ A_k \subset A_{k-1} $)} \\
|
||||
\end{align*}
|
||||
|
||||
We will try to show that $ \forall k \geq 2 $, $ P(A_k) = \frac{1}{k!} $. To do
|
||||
so, we will use induction to prove the following proposition \eqref{eq:induction},
|
||||
$ \forall k \geq 2 $:
|
||||
|
||||
\begin{equation}
|
||||
\label{eq:induction}
|
||||
\tag{$ \mathcal{H}_k $}
|
||||
P(U_1 + U_2 + \ldots + U_{k-1} < a) = \frac{a^k}{k!} \qquad \forall a \in [0, 1],
|
||||
\end{equation}
|
||||
|
||||
Let us denote $ S_k = U_1 + U_2 + \ldots + U_{k-1} \qquad \forall k \geq 2 $.
|
||||
|
||||
\paragraph{Base cases} $ k = 2 $ : $ P(U_1 < a) = a \neq \frac{a^2}{2}$ supposedly proving $ (\mathcal{H}_2) $.
|
||||
|
||||
$ k = 2 $ : \[ P(U_1 + U_2 < a) = \iint_{\cal{D}} f_{U_1, U_2}(x, y) \cdot (x + y) dxdy \]
|
||||
|
||||
Where $ \mathcal{D} = \{ (x, y) \in [0, 1]^2 \mid x + y < a \} $.
|
||||
|
||||
$ U_1 $ and $ U_2 $ are independent, so
|
||||
\begin{align*}
|
||||
f_{U_1, U_2}(x, y) & = f_{U_1}(x) \cdot f_{U_2}(y) \\
|
||||
& = \begin{cases}
|
||||
1 & \text{if } x \in [0, 1] \text{ and } y \in [0, 1] \\
|
||||
0 & \text{otherwise} \\
|
||||
\end{cases} \\
|
||||
\end{align*}
|
||||
|
||||
Hence,
|
||||
|
||||
\begin{align*}
|
||||
P(U_1 + U_2 < a)
|
||||
& = \iint_{\cal{D}} (x + y)dxdy \\
|
||||
& = \int_{0}^{a} \int_{0}^{a - x} (x + y) dy dx \\
|
||||
& = \int_{0}^{a} \left[ xy + \frac{y^2}{2} \right]_{y=0}^{y=a - x} dx \\
|
||||
& = \int_{0}^{a} \left( ax - x^2 + \frac{a^2}{2} - ax + \frac{x^2}{2} \right) dx \\
|
||||
& = \int_{0}^{a} \left( \frac{a^2}{2} - \frac{x^2}{2} \right) dx \\
|
||||
& = \left[ \frac{a^2 x}{2} - \frac{x^3}{6} \right]_{0}^{a} \\
|
||||
& = \frac{a^3}{2} - \frac{a^3}{6} \\
|
||||
\end{align*}
|
||||
|
||||
|
||||
\paragraph{Induction step} For a fixed $ k > 2 $, we assume that $
|
||||
(\mathcal{H}_{k-1}) $ is true. We will try to prove $ (\mathcal{H}_{k}) $.
|
||||
|
||||
\[
|
||||
P(S_{k-1} + U_{k-1} < a)
|
||||
= \iint_{\cal{D}} f_{S_{k-1}, U_{k-1}}(x, y) \cdot (x + y) dxdy \\
|
||||
\]
|
||||
where $ \mathcal{D} = \{ (x, y) \in [0, 1]^2 \mid x + y < a \} $.
|
||||
As $ S_{k-1} $ and $ U_{k-1} $ are independent,
|
||||
\[
|
||||
P(S_{k-1} + U_{k-1} < a)
|
||||
= \iint_{\cal{D}} f_{S_{k-1}}(x) \cdot f_{U_{k-1}}(y) \cdot (x + y) dxdy \qquad \\
|
||||
\]
|
||||
|
||||
$ (\mathcal{H}_{k-1}) $ gives us that $ \forall x \in [0, 1] $,
|
||||
$ F_{S_{k-1}}(x) = P(S_{k-1} < x) = \frac{x^{k-1}}{(k-1)!} $.
|
||||
|
||||
By differentiating, we get that $ \forall x \in [0, 1] $,
|
||||
|
||||
\[
|
||||
f_{S_{k-1}}(x) = F'_{S_{k-1}}(x) = \frac{x^{k-2}}{(k-2)!}
|
||||
\]
|
||||
|
||||
Furthermore, $ U_{k-1} $ is uniformly distributed on $ [0, 1] $, so
|
||||
$ f_{U_{k-1}}(y) = 1 $.
|
||||
|
||||
\begin{align*}
|
||||
\text{Hence, }
|
||||
P(S_{k-1} + U_{k-1} < a)
|
||||
& =
|
||||
& = \frac{a^{k}}{k!}
|
||||
\end{align*}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\section{Complexity and implementation optimization}
|
||||
|
||||
Both the NFBP and NFDBP algorithms have a linear complexity $ O(n) $, as we
|
||||
only need to iterate over the items once. While the algorithms themselves are
|
||||
linear, calculating the statistics may not not be. In this section, we will
|
||||
discuss how to optimize the implementation of the statistical analysis.
|
||||
|
||||
\subsection{Performance optimization}
|
||||
|
||||
When implementing the statistical analysis, the intuitive way to do it is to
|
||||
run $ R $ simulations, store the results, then conduct the analysis. However,
|
||||
when running a large number of simulations, this can be very memory
|
||||
consuming. We can optimize the process by computing the statistics on the fly,
|
||||
by using sum formulae. This uses nearly constant memory, as we only need to
|
||||
store the current sum and the current sum of squares for different variables.
|
||||
|
||||
While the mean can easily be calculated by summing then dividing, the empirical
|
||||
variance can be calculated using the following formula:
|
||||
|
||||
\begin{align*}
|
||||
{S_N}^2 & = \frac{1}{N-1} \sum_{i=1}^{N} (X_i - \overline{X})^2 \\
|
||||
& = \frac{1}{N-1} \sum_{i=1}^{N} X_i^2 - \frac{N}{N-1} \overline{X}^2
|
||||
\end{align*}
|
||||
|
||||
The sum $ \frac{1}{N-1} \sum_{i=1}^{N} X_i^2 $ can be calculated iteratively
|
||||
after each simulation.
|
||||
|
||||
\subsection{Effective resource consumption}
|
||||
|
||||
We set out to study the resource consumption of the algorithms. We implemented
|
||||
the above formulae to calculate the mean and variance of $ N = 10^6 $ random
|
||||
numbers. We wrote the following algorithms \footnotemark :
|
||||
|
||||
\footnotetext{The full code used to measure performance can be found in Annex \ref{annex:performance}.}
|
||||
|
||||
\paragraph{Intuitive algorithm} Store values first, calculate later
|
||||
|
||||
\begin{lstlisting}[language=python]
|
||||
N = 10**6
|
||||
values = [random() for _ in range(N)]
|
||||
mean = mean(values)
|
||||
variance = variance(values)
|
||||
\end{lstlisting}
|
||||
|
||||
Execution time : $ 4.8 $ seconds
|
||||
|
||||
Memory usage : $ 32 $ MB
|
||||
|
||||
\paragraph{Improved algorithm} Continuous calculation
|
||||
|
||||
\begin{lstlisting}[language=python]
|
||||
N = 10**6
|
||||
Tot = 0
|
||||
Tot2 = 0
|
||||
for _ in range(N):
|
||||
item = random()
|
||||
Tot += item
|
||||
Tot2 += item ** 2
|
||||
mean = Tot / N
|
||||
variance = Tot2 / (N-1) - mean**2
|
||||
\end{lstlisting}
|
||||
|
||||
Execution time : $ 530 $ milliseconds
|
||||
|
||||
Memory usage : $ 1.3 $ kB
|
||||
|
||||
\paragraph{Analysis} Memory usage is, as expected, much lower when calculating
|
||||
the statistics on the fly. Furthermore, something we hadn't anticipated is the
|
||||
execution time. The improved algorithm is nearly 10 times faster than the
|
||||
intuitive one. This can be explained by the time taken to allocate memory and
|
||||
then calculate the statistics (which iterates multiple times over the array).
|
||||
\footnotemark
|
||||
|
||||
\footnotetext{Performance was measured on a single computer and will vary
|
||||
between devices. Execution time and memory usage do not include the import of
|
||||
libraries.}
|
||||
|
||||
\subsection{NFBP vs NFDBP}
|
||||
|
||||
\subsection{Optimal algorithm}
|
||||
|
||||
\cite{bin-packing-approximation:2022}
|
||||
|
||||
\sectionnn{Conclusion}
|
||||
|
BIN
latex/cover/charte_graphique.pdf
Normal file
BIN
latex/cover/charte_graphique.pdf
Normal file
Binary file not shown.
30
latex/cover/cover_in.tex
Normal file
30
latex/cover/cover_in.tex
Normal file
|
@ -0,0 +1,30 @@
|
|||
\input{main_variables}
|
||||
\pagenumbering{gobble}
|
||||
|
||||
% Couverture
|
||||
\thispagestyle{empty}
|
||||
\definecolor{insa_blue}{RGB}{52,83,111}
|
||||
\definecolor{insa_red}{RGB}{230,39,20}
|
||||
\noindent\begin{tikzpicture}[remember picture, overlay, shift={(current page.south west)}]
|
||||
\draw[draw=none, fill=insa_red] (12.32,1.24) -- (12.32,4.94) -- (19.7,4.94) -- (19.7,1.24) -- cycle;
|
||||
\node[anchor=north west, align=left, color=white, text width=12cm] at (2.3,23.5) {\varmaintitle};
|
||||
\node[anchor=north west, align=left, color=white, text width=8cm] at (2.3,22.5) {\varmainsubtitle};
|
||||
% \node[anchor=north west] at (2.3,21.5) {\includegraphics[scale=1.00]{\varlogo}};
|
||||
\node[anchor=north west, align=left, color=white, text width=12cm] at (2.3,16) {\varcovertext};
|
||||
%\node[anchor=center, align=center, text width=12cm] at (10,6.7) {\color{black} \varcovertext}; %-3, 4.1
|
||||
\node[anchor=north west, align=left, text width=12cm] at (1.2,4.7) {\varinsaaddress};
|
||||
% \node[anchor=north west, align=left, color=white, text width=12cm] at (12.5,4.7) {\varcompanyaddress};
|
||||
\node[anchor=north west, align=left, text width=12cm] at (0.5,4) {\includepdf[pages={1}]{cover/charte_graphique}};
|
||||
\end{tikzpicture}
|
||||
\newpage
|
||||
|
||||
% % Page de garde
|
||||
% \thispagestyle{empty}
|
||||
% \noindent\begin{tikzpicture}[remember picture, overlay, shift={(current page.south west)}]
|
||||
% \node[anchor=north west, align=left, text width=10cm] at (2.3,23.5) {\color{black} \varmaintitle};
|
||||
% \node[anchor=north west, align=left, text width=8cm] at (2.3,22.5) {\varmainsubtitle};
|
||||
% \node[anchor=north west, align=left, text width=12cm] at (2.3,16) {\color{black} \varcovertext};
|
||||
% \node[anchor=north west, align=left, text width=12cm] at (1.2,4.7) {\varinsaaddress};
|
||||
% \node[anchor=north west, align=left, text width=12cm] at (12.5,4.7) {\color{black} \varcompanyaddress};
|
||||
% \end{tikzpicture}
|
||||
% \newpage
|
21
latex/cover/cover_out.tex
Normal file
21
latex/cover/cover_out.tex
Normal file
|
@ -0,0 +1,21 @@
|
|||
\newpage
|
||||
\pagenumbering{gobble}
|
||||
\thispagestyle{empty}
|
||||
\definecolor{insa_blue}{RGB}{52,83,111}
|
||||
\definecolor{insa_red}{RGB}{226,50,46}
|
||||
\noindent\begin{tikzpicture}[remember picture, overlay, shift={(current page.south west)}]
|
||||
% \draw[draw=none, path fading=east, left color=insa_blue, right color=insa_blue!25!white] (21,7.3) -- (4.3,16.05) -- (21,24.8) -- cycle;
|
||||
% \draw[draw=none, path fading=east, left color=insa_blue, right color=insa_blue!60!white] (0,16.2) -- (7,19.75) -- (0,23.1) -- cycle;
|
||||
% \draw[draw=none, path fading=east, left color=insa_blue, right color=insa_blue!25!white] (0,17.3) -- (13.7,24.5) -- (2.3,29.7) -- (0,29.7) -- cycle;
|
||||
%
|
||||
%
|
||||
% \draw[draw=none, fill=insa_red] (6.2,0) -- (6.2,1.2) -- (11.6,0) -- cycle;
|
||||
%
|
||||
% \draw[draw=none, fill=white] (0,0) -- (0,10) -- (10,10) -- (10,0) -- cycle;
|
||||
% \node[anchor=south west, align=left] at (1.25,3.6) {\textbf{INSA Toulouse}};
|
||||
% \node[anchor=south west, align=left] at (1.25,2.20) {135, Avenue de Rangueil \\ 31077 Toulouse Cedex 4 - France \\ \href{http://www.insa-toulouse.fr}{www.insa-toulouse.fr}};
|
||||
%
|
||||
% \node[anchor=south west] at (11.1,2.2) {\includegraphics[height=1cm, keepaspectratio]{cover/meta/univ.png}};
|
||||
%\node[anchor=south west] at (13.4,2.2) {\includegraphics[height=1cm, keepaspectratio]{cover/meta/ministere.png}};
|
||||
% \node[anchor=north west, align=left, text width=12cm] at (0.5,4) {\includepdf[pages={2}]{cover/charte_graphique}};
|
||||
\end{tikzpicture}
|
3
latex/cover/covermain.tex
Normal file
3
latex/cover/covermain.tex
Normal file
|
@ -0,0 +1,3 @@
|
|||
\AtBeginDocument{\input{cover/cover_in.tex}\pagenumbering{arabic}}
|
||||
|
||||
%\AtEndDocument{\input{cover/cover_out.tex}}
|
BIN
latex/graphics/fraiseuse.jpg
Normal file
BIN
latex/graphics/fraiseuse.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
139
latex/main.tex
Normal file
139
latex/main.tex
Normal file
|
@ -0,0 +1,139 @@
|
|||
\documentclass[a4paper,11pt,twoside]{article}
|
||||
%\pdfminorversion=7 % To use charte graphique (pdf 1.7)
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{lscape}
|
||||
\usepackage{boldline,multirow,tabularx,colortbl,diagbox,makecell,fancybox}
|
||||
\usepackage{amsfonts,amssymb,amsmath,mathrsfs,array}
|
||||
\usepackage{pgf,tikz,xcolor}
|
||||
\usetikzlibrary{calc,positioning,shapes.geometric,shapes.symbols,shapes.misc, fit, shapes, arrows, arrows.meta,fadings,through}
|
||||
\usepackage[top=2cm, bottom=2cm, left=4cm, right=4cm]{geometry}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{titlesec}
|
||||
\usepackage{eurosym}
|
||||
\usepackage[english]{babel}
|
||||
\usepackage{eso-pic} % for background on cover
|
||||
\usepackage{listings}
|
||||
\usepackage{tikz}
|
||||
|
||||
% Define colors for code
|
||||
\definecolor{codegreen}{rgb}{0,0.4,0}
|
||||
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
|
||||
\definecolor{codepurple}{rgb}{0.58,0,0.82}
|
||||
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
|
||||
|
||||
\lstdefinestyle{mystyle}{
|
||||
backgroundcolor=\color{backcolour},
|
||||
commentstyle=\color{codegreen},
|
||||
keywordstyle=\color{magenta},
|
||||
numberstyle=\tiny\color{codegray},
|
||||
stringstyle=\color{codepurple},
|
||||
basicstyle=\ttfamily\small,
|
||||
breakatwhitespace=false,
|
||||
breaklines=true,
|
||||
captionpos=b,
|
||||
keepspaces=true,
|
||||
numbers=left,
|
||||
numbersep=5pt,
|
||||
showspaces=false,
|
||||
showstringspaces=false,
|
||||
showtabs=false,
|
||||
tabsize=2
|
||||
}
|
||||
|
||||
\lstset{style=mystyle}
|
||||
|
||||
|
||||
% table des annexes
|
||||
\usepackage{minitoc}
|
||||
\usepackage{pdfpages}
|
||||
|
||||
\usepackage[style=iso-alphabetic]{biblatex}
|
||||
\addbibresource{bibliography.bib}
|
||||
|
||||
|
||||
\input{advanced.params/tikz.conf}
|
||||
\input{advanced.params/misc.commands}
|
||||
\input{cover/covermain.tex}
|
||||
|
||||
\date{\today}
|
||||
|
||||
\begin{document}
|
||||
\dosecttoc{} % generate TOC
|
||||
|
||||
|
||||
% % Remerciements
|
||||
% \thispagestyle{empty} % removes page number
|
||||
% \subsection*{Remerciements}
|
||||
% \input{remerciements}
|
||||
% \clearpage
|
||||
|
||||
|
||||
% TABLE DES MATIÈRES
|
||||
\thispagestyle{empty} % removes page number
|
||||
\setcounter{secnumdepth}{3}
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
|
||||
|
||||
% Contenu
|
||||
\setcounter{page}{1}
|
||||
\include{content}
|
||||
|
||||
|
||||
% BIBLIOGRAPHIE
|
||||
\addcontentsline{toc}{section}{Bibliography}
|
||||
\printbibliography[title={Bibliography}]
|
||||
|
||||
|
||||
|
||||
% TABLE DES ANNEXES
|
||||
\clearpage
|
||||
\appendix
|
||||
% \thispagestyle{empty} % removes page number
|
||||
\sectionnn{Table des Annexes}
|
||||
% Désactivation de la table des matières
|
||||
\addtocontents{toc}{\protect\setcounter{tocdepth}{0}}
|
||||
% Personnalisation de la table des annexes
|
||||
\renewcommand{\stctitle}{} % Titre (issue with previous subsection showing up)
|
||||
\renewcommand\thesubsection{A\arabic{subsection}} % Numérotation
|
||||
\renewcommand{\stcSSfont}{} % Police normale, pas en gras
|
||||
\mtcsetrules{secttoc}{off} % Désactivation des lignes en haut et en bas de la table
|
||||
% Affichage de la table des annexes
|
||||
\secttoc
|
||||
|
||||
|
||||
% ANNEXES
|
||||
\clearpage
|
||||
\pagenumbering{Roman}
|
||||
|
||||
\subsection{Performance analysis script}
|
||||
\label{annex:performance}
|
||||
|
||||
\input{annex-performance}
|
||||
|
||||
\clearpage
|
||||
|
||||
\subsection{Probabilistic analysis script}
|
||||
\label{annex:probabilistic}
|
||||
|
||||
\input{annex-probabilistic}
|
||||
|
||||
\clearpage
|
||||
|
||||
% \includepdf[pages={1}, scale=0.96,
|
||||
% pagecommand=\subsection{Questionnaire 1 : Sensibilisation à l’Hygiène et à la Sécurité}]
|
||||
% {questionnaires}
|
||||
% \clearpage
|
||||
%
|
||||
%
|
||||
% \includepdf[pages={2}, scale=0.96,
|
||||
% pagecommand=\subsection{Questionnaire 2 : Sensibilisation à l’innovation en entreprise}]
|
||||
% {questionnaires}
|
||||
% \clearpage
|
||||
%
|
||||
\includepdf[pages={2}, scale=1]
|
||||
{cover/charte_graphique}
|
||||
|
||||
\mtcsetrules{secttoc}{off}
|
||||
\end{document}
|
34
latex/main_variables.tex
Normal file
34
latex/main_variables.tex
Normal file
|
@ -0,0 +1,34 @@
|
|||
\def\varmaintitle{
|
||||
\textbf{\Huge{One-dimensional box fitting}}
|
||||
}
|
||||
|
||||
\def\varmainsubtitle{
|
||||
\LARGE{A statistical analysis of different algorithms}
|
||||
}
|
||||
|
||||
% \def\varlogo{logo.png} %ou 5 ou 13
|
||||
|
||||
\def\varcovertext{
|
||||
\textbf{Clément LACAU}
|
||||
|
||||
\textbf{Paul ALNET}
|
||||
|
||||
2MIC B - Year 59
|
||||
|
||||
\vspace{0.33cm}
|
||||
|
||||
%\begin{center}
|
||||
% -\hspace{0.25cm}Version du \today\hspace{0.25cm}-
|
||||
%\end{center}
|
||||
Defense on June Xth 2023 % TODO
|
||||
}
|
||||
|
||||
\def\varinsaaddress{
|
||||
\textbf{INSA Toulouse}
|
||||
|
||||
135, Avenue de Rangueil
|
||||
|
||||
31077 Toulouse Cedex 4 - France
|
||||
|
||||
\href{https://www.insa-toulouse.fr}{www.insa-toulouse.fr}
|
||||
}
|
29
latex/remerciements.tex
Normal file
29
latex/remerciements.tex
Normal file
|
@ -0,0 +1,29 @@
|
|||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Tortor pretium
|
||||
viverra suspendisse potenti nullam ac tortor vitae. Porttitor massa id
|
||||
neque aliquam vestibulum morbi blandit. Quis imperdiet massa tincidunt
|
||||
nunc pulvinar sapien et ligula. Tincidunt lobortis feugiat vivamus
|
||||
at. Amet justo donec enim diam. Ut tortor pretium viverra suspendisse
|
||||
potenti nullam ac tortor vitae. Consectetur a erat nam at lectus urna
|
||||
duis convallis convallis. Viverra nam libero justo laoreet sit amet
|
||||
cursus. Non enim praesent elementum facilisis leo. Sit amet mauris
|
||||
commodo quis. Lectus mauris ultrices eros in cursus turpis. Cursus euismod
|
||||
quis viverra nibh cras pulvinar mattis. Duis at consectetur lorem donec
|
||||
massa sapien faucibus. In hac habitasse platea dictumst quisque sagittis
|
||||
purus. Ut aliquam purus sit amet. Eget egestas purus viverra accumsan
|
||||
in nisl. Egestas dui id ornare arcu odio ut sem. Nunc mi ipsum faucibus
|
||||
vitae. Vel pretium lectus quam id leo in vitaLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Tortor pretium
|
||||
viverra suspendisse potenti nullam ac tortor vitae. Porttitor massa id
|
||||
neque aliquam vestibulum morbi blandit. Quis imperdiet massa tincidunt
|
||||
nunc pulvinar sapien et ligula. Tincidunt lobortis feugiat vivamus
|
||||
at. Amet justo donec enim diam. Ut tortor pretium viverra suspendisse
|
||||
potenti nullam ac tortor vitae. Consectetur a erat nam at lectus urna
|
||||
duis convallis convallis. Viverra nam libero justo laoreet sit amet
|
||||
cursus. Non enim praesent elementum facilisis leo. Sit amet mauris
|
||||
commodo quis. Lectus mauris ultrices eros in cursus turpis. Cursus euismod
|
||||
quis viverra nibh cras pulvinar mattis. Duis at consectetur lorem donec
|
||||
massa sapien faucibus. In hac habitasse platea dictumst quisque sagittis
|
||||
purus. Ut aliquam purus sit amet. Eget egestas purus viverra accumsan
|
||||
in nisl. Egestas dui id ornare arcu odio ut sem. Nunc mi ipsum faucibus
|
||||
vitae. Vel pretium lectus quam id leo in vitae
|
Loading…
Reference in a new issue