Ottimizzazione della Produzione e Gestione Scorte: Modello di Programmazione Lineare Intera e Implementazione Python

Cerca:

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
Ottimizzazione produzione e scorte

Introduzione

Immagina un’azienda che produce turbine eoliche su commessa. Ogni turbina richiede migliaia di componenti, alcuni dei quali sono unici e realizzati su misura. Le commesse durano anni e la manutenzione delle turbine installate è essenziale per garantire la produzione di energia. Un guasto a un componente critico può fermare la turbina, causando perdite significative.

In questo scenario, la gestione efficiente delle scorte di ricambio è vitale. L’azienda deve prevedere la domanda futura, ottimizzare la produzione e lo stoccaggio, e garantire che i componenti giusti siano disponibili al momento giusto. L’ottimizzazione diventa cruciale per bilanciare i costi di produzione e stoccaggio con il rischio di fermi macchina.

Lo scenario nel dettaglio

Una multinazionale di ingegneria elettrica produce su commessa per pochi clienti, con progetti multiannuali. La gestione delle parti di ricambio è fondamentale per evitare rotture di stock, dando priorità alle commesse più vecchie. L’azienda deve ottimizzare la produzione e lo stoccaggio delle parti di ricambio considerando: capacità produttiva, capacità di magazzino, costo di produzione e di stoccaggio, domanda specifica per ogni commessa, turnover delle scorte. L’obiettivo del modello è minimizzare i costi mantenendo un equilibrio tra produzione, domanda e capacità logistiche.

2. Definizione del Problema

2.1 Obiettivi

Il problema è un modello di programmazione lineare intera con i seguenti obiettivi:

  • Minimizzare il costo totale (produzione + stoccaggio).
  • Soddisfare la domanda prevista senza rotture di stock.
  • Dare priorità alle commesse più vecchie.
  • Limitare la produzione in base alla capacità produttiva.
  • Limitare lo spazio occupato in base alla capacità del magazzino.
  • Mantenere un turnover delle scorte, evitando accumuli eccessivi.

2.2 Variabili Decisionali

  • Produzione: [math]x_{c,p}[/math] (quantità prodotta della parte [math]p[/math] per la commessa [math]c[/math]).
  • Scorte finali: [math]S_p[/math] (quantità della parte [math]p[/math] in magazzino dopo la domanda).

Entrambe le variabili sono intere non negative.

3. Formulazione Matematica

3.1 Notazione

Simbolo Descrizione
[math]C[/math] Insieme delle commesse
[math]P[/math] Insieme delle parti di ricambio
[math]D_{c,p}[/math] Domanda della parte [math]p[/math] per la commessa [math]c[/math]
[math]x_{c,p}[/math] Quantità prodotta della parte [math]p[/math] per la commessa [math]c[/math]
[math]S_p[/math] Scorte finali della parte [math]p[/math] in magazzino
[math]C_{prod,p}[/math] Costo unitario di produzione della parte [math]p[/math]
[math]C_{stocc,p}[/math] Costo unitario di stoccaggio della parte [math]p[/math]
[math]V_p[/math] Volume unitario della parte [math]p[/math]
[math]S_{att,p}[/math] Scorte iniziali disponibili della parte [math]p[/math]
[math]C_{tot}[/math] Capacità massima di produzione nel periodo
[math]C_{p,p}[/math] Capacità massima di produzione per singola parte
[math]C_{mag}[/math] Capacità massima del magazzino

3.2 Funzione Obiettivo

Minimizziamo il costo totale:

[math]\min \sum_{c \in C} \sum_{p \in P} C_{prod,p} \cdot x_{c,p} + \sum_{p \in P} C_{stocc,p} \cdot S_p[/math]

3.3 Vincoli

  1. Soddisfazione della domanda:[math]\sum_{c \in C} x_{c,p} + S_{att,p} = \sum_{c \in C} D_{c,p} + S_p, \quad \forall p \in P[/math]
  2. Priorità alle commesse più vecchie:[math]\sum x_{c_i, p} \geq \sum x_{c_{i+1}, p}, \quad \forall p \in P, \forall i = 1, \dots, |C|-1[/math]
  3. Capacità produttiva totale:[math]\sum_{c \in C} \sum_{p \in P} x_{c,p} \leq C_{tot}[/math]
  4. Capacità produttiva per singola parte:[math]\sum_{c \in C} x_{c,p} \leq C_{p,p}, \quad \forall p \in P[/math]
  5. Capacità del magazzino:[math]\sum_{p \in P} V_p \cdot S_p \leq C_{mag}[/math]
  6. Turnover delle scorte:[math]S_p \leq 0.3 \cdot \sum_{c \in C} x_{c,p}, \quad \forall p \in P[/math]
Forse potrebbe interessarti anche:  Analisi Strategica dei Modelli di Risparmio negli Stati Uniti: Uno Studio su Dati Simulati con Clustering K-Means

Implementazione in Python

L’implementazione di un modello di ottimizzazione come il seguente offre numerosi vantaggi:

  • Riduzione dei costi: Minimizzando i costi di produzione e stoccaggio, l’azienda può aumentare la sua competitività.
  • Aumento dell’efficienza: Ottimizzando la produzione e la gestione delle scorte, l’azienda può ridurre i tempi di consegna e migliorare la sua capacità di risposta alla domanda.
  • Maggiore soddisfazione del cliente: Garantendo la disponibilità dei componenti di ricambio, l’azienda può ridurre i tempi di fermo macchina e aumentare la soddisfazione del cliente.
  • Migliore pianificazione: Il modello fornisce una base solida per la pianificazione della produzione e la gestione delle scorte, consentendo all’azienda di prendere decisioni più informate.
  • Riduzione degli sprechi: Un’ottimizzazione efficace riduce la probabilità di sovrapproduzione o obsolescenza delle scorte.

L’implementazione usa PuLP, una libreria per la programmazione lineare in Python.

Il codice segue la formulazione sopra e include:

 

Dati di input e definizione delle variabili per l’ottimizzazione della produzione di parti di ricambio

1. Dati di Input

Commesse

C1, C2, C3 (ordinate dalla più vecchia alla più recente).

Parti di ricambio

P1, P2, P3, P4.

Domanda

La quantità richiesta di ciascuna parte per ogni commessa è definita come segue:

Commessa P1 P2 P3 P4
C1 10 5 7 3
C2 8 6 5 2
C3 6 4 3 1

Costi di produzione

Il costo per produrre una unità di ciascuna parte è:

Parte Costo di produzione
P1 2.0
P2 3.0
P3 1.5
P4 4.0

Costi di stoccaggio

Il costo per mantenere in magazzino una unità di ciascuna parte è:

Parte Costo di stoccaggio
P1 0.5
P2 0.3
P3 0.2
P4 0.7

Scorte attuali

La quantità di ciascuna parte attualmente disponibile in magazzino è:

Parte Scorte attuali
P1 5
P2 3
P3 2
P4 1

Capacità produttiva

    • Capacità totale di produzione: 50 unità.
    • Capacità per singola parte:
Parte Capacità produttiva
P1 20
P2 15
P3 10
P4 5

Capacità del magazzino

    • Capacità totale del magazzino: 100 unità di volume.
    • Volume occupato da ciascuna parte:
Parte Volume per unità
P1 3
P2 2
P3 1
P4 4

2. Definizione delle Variabili

  • produzione[c, p]: Quantità di parte [math]p[/math] prodotta per la commessa [math]c[/math] (variabile intera).
    Esempio: produzione["C1", "P1"] rappresenta la quantità di P1 prodotta per C1.
  • scorte_finali[p]: Quantità di parte [math]p[/math] rimanente in magazzino alla fine del periodo (variabile intera).
    Esempio: scorte_finali["P1"] rappresenta la quantità di P1 in magazzino alla fine del periodo.

 

3. Funzione Obiettivo

Minimizzare i costi totali, che includono:

Costi di produzione:

[math]\sum_{c \in \text{commesse}} \sum_{p \in \text{parti}} \text{costo_produzione}[p] \cdot \text{produzione}[c, p][/math]

Costi di stoccaggio:

[math]\sum_{p \in \text{parti}} \text{costo_stoccaggio}[p] \cdot \text{scorte_finali}[p][/math]

La funzione obiettivo è:

Minimizzare

[math]2.0 \cdot \text{produzione}[C1, P1] + 3.0 \cdot \text{produzione}[C1, P2] + 1.5 \cdot \text{produzione}[C1, P3] + 4.0 \cdot \text{produzione}[C1, P4] +[/math]

[math]2.0 \cdot \text{produzione}[C2, P1] + 3.0 \cdot \text{produzione}[C2, P2] + 1.5 \cdot \text{produzione}[C2, P3] + 4.0 \cdot \text{produzione}[C2, P4] +[/math]

[math]2.0 \cdot \text{produzione}[C3, P1] + 3.0 \cdot \text{produzione}[C3, P2] + 1.5 \cdot \text{produzione}[C3, P3] + 4.0 \cdot \text{produzione}[C3, P4] +[/math]

Forse potrebbe interessarti anche:  Modello Input-Output di : Come le Matrici Rivoluzionano l'Analisi Economica Settoriale

[math]0.5 \cdot \text{scorte_finali}[P1] + 0.3 \cdot \text{scorte_finali}[P2] + 0.2 \cdot \text{scorte_finali}[P3] + 0.7 \cdot \text{scorte_finali}[P4][/math]

Questa funzione rappresenta la somma dei costi di produzione e dei costi di stoccaggio per tutte le parti e le commesse.

 

4. Vincoli

Vincolo 1: Bilancio delle scorte

Per ogni parte [math]p[/math], la somma della produzione e delle scorte attuali deve soddisfare la domanda e le scorte finali:

 

[math]\sum_{c \in \text{commesse}} \text{produzione}[c, p] + \text{scorte_attuali}[p] = \sum_{c \in \text{commesse}} \text{domanda}[c][p] + \text{scorte_finali}[p][/math]

 

Vincolo 2: Priorità delle commesse

Per ogni parte [math]p[/math], la produzione per le commesse più vecchie deve essere maggiore o uguale a quella per le commesse più recenti:

 

[math]\text{produzione}[C1, p] \geq \text{produzione}[C2, p] \geq \text{produzione}[C3, p][/math]

 

Vincolo 3: Capacità produttiva totale

La produzione totale non deve superare la capacità produttiva totale:

 

[math]\sum_{c \in \text{commesse}} \sum_{p \in \text{parti}} \text{produzione}[c, p] \leq 50[/math]

 

Vincolo 4: Capacità produttiva per singola parte

Per ogni parte [math]p[/math], la produzione totale non deve superare la capacità produttiva della parte:

 

[math]\sum_{c \in \text{commesse}} \text{produzione}[c, p] \leq \text{capacita_per_parte}[p][/math]

 

Vincolo 5: Capacità del magazzino

Le scorte finali non devono superare la capacità del magazzino:

 

[math]\sum_{p \in \text{parti}} \text{volume_per_parte}[p] \cdot \text{scorte_finali}[p] \leq 100[/math]

 

Vincolo 6: Turnover delle scorte

Per ogni parte [math]p[/math], le scorte finali non devono superare il 30% della produzione totale:

 

[math]\text{scorte_finali}[p] \leq 0.3 \cdot \sum_{c \in \text{commesse}} \text{produzione}[c, p][/math]

 

5. Risoluzione del Problema

Il modello viene risolto utilizzando il risolutore CBC (incluso in PuLP).

Il codice completo:

from pulp import LpMaximize, LpProblem, LpVariable, lpSum, PULP_CBC_CMD

# ===========================================
# 1. Dati di input
# ===========================================

# Commesse ordinate dalla più vecchia alla più recente
commesse = ["C1", "C2", "C3"]

# Parti di ricambio
parti = ["P1", "P2", "P3", "P4"]

# Domanda di ciascuna parte per ogni commessa
domanda = {
    "C1": {"P1": 10, "P2": 5, "P3": 7, "P4": 3},
    "C2": {"P1": 8, "P2": 6, "P3": 5, "P4": 2},
    "C3": {"P1": 6, "P2": 4, "P3": 3, "P4": 1},
}

# Costi di produzione per ciascuna parte
costi_produzione = {"P1": 2, "P2": 3, "P3": 1.5, "P4": 4}

# Costi di stoccaggio per ciascuna parte
costi_stoccaggio = {"P1": 0.5, "P2": 0.3, "P3": 0.2, "P4": 0.7}

# Scorte attuali di ciascuna parte
scorte_attuali = {"P1": 5, "P2": 3, "P3": 2, "P4": 1}

# Capacità produttiva totale e per singola parte
capacita_totale = 50
capacita_per_parte = {"P1": 20, "P2": 15, "P3": 10, "P4": 5}

# Capacità del magazzino e volumi occupati da ciascuna parte
capacita_magazzino = 100
volume_per_parte = {"P1": 3, "P2": 2, "P3": 1, "P4": 4}

# ===========================================
# 2. Definizione del modello e delle variabili
# ===========================================

# Creazione del modello di ottimizzazione
model = LpProblem("Ottimizzazione_Magazzino", LpMaximize)

# Variabili decisionali:
# - produzione[c, p]: quantità di parte p prodotta per la commessa c
# - scorte_finali[p]: quantità di parte p rimanente in magazzino alla fine del periodo
produzione = {
    (c, p): LpVariable(f"Produzione_{c}_{p}", lowBound=0, cat="Integer")
    for c in commesse for p in parti
}
scorte_finali = {
    p: LpVariable(f"Scorte_Finali_{p}", lowBound=0, cat="Integer")
    for p in parti
}

# ===========================================
# 3. Definizione della funzione obiettivo
# ===========================================

# Obiettivo: minimizzare i costi totali di produzione e stoccaggio
model += (
    lpSum(costi_produzione[p] * produzione[c, p] for c in commesse for p in parti) +
    lpSum(costi_stoccaggio[p] * scorte_finali[p] for p in parti),
    "Minimizzazione_Costi_Totali"
)

# ===========================================
# 4. Definizione dei vincoli
# ===========================================

# Vincolo 1: soddisfare la domanda con scorte disponibili + nuova produzione
for p in parti:
    model += (
        lpSum(produzione[c, p] for c in commesse) + scorte_attuali.get(p, 0) ==
        lpSum(domanda[c][p] for c in commesse) + scorte_finali[p],
        f"Bilancio_Scorte_{p}"
    )

# Vincolo 2: priorità alle commesse più vecchie
for i in range(len(commesse) - 1):
    c1, c2 = commesse[i], commesse[i + 1]
    for p in parti:
        model += (
            lpSum(produzione[c1, p]) >= lpSum(produzione[c2, p]),
            f"Priorità_{p}_{c1}_{c2}"
        )

# Vincolo 3: capacità produttiva totale
model += (
    lpSum(produzione[c, p] for c in commesse for p in parti) <= capacita_totale,
    "Capacità_Totale"
)

# Vincolo 4: capacità produttiva per singola parte
for p in parti:
    model += (
        lpSum(produzione[c, p] for c in commesse) <= capacita_per_parte[p],
        f"Capacità_{p}"
    )

# Vincolo 5: capacità del magazzino
model += (
    lpSum(volume_per_parte[p] * scorte_finali[p] for p in parti) <= capacita_magazzino,
    "Capacità_Magazzino"
)

# Vincolo 6: turnover delle scorte (massimo il 30% della produzione totale può restare in stock)
for p in parti:
    model += (
        scorte_finali[p] <= 0.3 * lpSum(produzione[c, p] for c in commesse),
        f"Turnover_{p}"
    )

# ===========================================
# 5. Risoluzione del problema
# ===========================================

# Risoluzione del modello utilizzando il risolutore CBC
model.solve(PULP_CBC_CMD(msg=True))

# ===========================================
# 6. Stampa dei risultati
# ===========================================

# Stampa della produzione per ciascuna commessa e parte
print("Produzione:")
for c in commesse:
    for p in parti:
        print(f"Produzione {p} per {c}: {produzione[c, p].varValue}")

# Stampa delle scorte finali per ciascuna parte
print("\nScorte finali:")
for p in parti:
    print(f"Scorte finali {p}: {scorte_finali[p].varValue}")

# Stampa del costo totale
print(f"\nCosto totale: {model.objective.value()}")

 

Forse potrebbe interessarti anche:  I PRAGMA di SQLite: Il Pannello di Controllo Segreto che Trasforma un File .db in un Motore Enterprise

6. Risultati

Produzione

Commessa P1 P2 P3 P4
C1 19 13 13 2
C2 0 0 0 2
C3 0 0 0 2

Scorte finali

Parte Scorte finali
P1 0
P2 1
P3 0
P4 0

Costo totale

Costo totale = 123.5

Spiegazione dei Risultati

  • Produzione:
    • La produzione è concentrata principalmente sulla commessa più vecchia (C1), rispettando il vincolo di priorità.
    • Per le commesse C2 e C3, la produzione è minima o nulla, poiché la capacità produttiva è stata quasi interamente utilizzata per C1.
  • Scorte finali:
    • Le scorte finali sono quasi tutte a zero, tranne per P2 che ha una scorte finale di 1 unità.
  • Costo totale:
    • Il costo totale minimizzato è 123.5, che include sia i costi di produzione che i costi di stoccaggio.

Possibili Estensioni del Modello: Verso un’Ottimizzazione Più Completa

Il modello presentato può essere esteso in diversi modi per affrontare ulteriori complessità:

  • Vincoli di qualità: Includere vincoli di qualità per garantire che i componenti prodotti soddisfino gli standard richiesti.
  • Gestione dei tempi di consegna: Considerare i tempi di consegna dei fornitori e i tempi di produzione per ottimizzare la pianificazione.
  • Ottimizzazione della logistica: Includere i costi di trasporto e i vincoli di capacità logistica nel modello.
  • Modelli di previsione della domanda: Utilizzare modelli di previsione più sofisticati per prevedere la domanda futura in modo più accurato.
  • Considerazione dell’obsolescenza: Includere la probabilità di obsolescenza dei componenti nel modello per evitare accumuli eccessivi di scorte.
Pubblicità