Calcoli scientifici con Julia/Ottimizzazione del budget personale
Template:Calcoli scientifici con Julia L’ottimizzazione del budget personale è un classico problema di ricerca operativa, in cui bisogna definire variabili di spesa, imporre vincoli di bilancio e scegliere una funzione obiettivo. In particolare si può costruire un modello lineare o non lineare con utilità logaritmica (funzione obiettivo) che deve essere massimizzata.
In termini matematici il problema lineare è con n categorie di spesa :
quello non lineare:
dove:
- è la spesa allocata alla categoria
- è il peso (importanza relativa) della categoria
- è il budget totale disponibile
- è la spesa minima obbligatoria per la categoria
- è la spesa massima ammissibile per la categoria
I pesi di utilità rappresentano quanto una certa spesa contribuisce al benessere o alla soddisfazione della persona. Ad esempio supponiamo tre categorie di spesa:
| Spesa | Peso di utilità | | ------ | --------------- | | cibo | 3 | | svago | 1 | | viaggi | 4 |
quindi:
- 1 € speso in viaggi dà più soddisfazione
- 1 € speso in cibo dà utilità media
- 1 € speso in svago dà meno utilità
Quindi il modello non lineare cercherà di allocare più budget nelle categorie con peso maggiore massimizzando:
con i relativi vincoli di bilancio del tipo :
nel modello lineare invece si massimizza :
con :
e
I pesi si scelgono per valutazione soggettiva oppure osservando dove si spende di più e cosa si preferisce sacrificare.
Nel modello non lineare si utilizza la funzione logaritmo perché si può dimostrare che la soluzione ottima del problema nel caso non vincolato risulta:
ovvero ogni categoria di spesa riceve una quota proporzionale al proprio peso indipendentemente dal budget totale B.
Nel modello lineare, la soluzione ottima è sempre ai vertici del poliedro dei vincoli, cioè ogni categoria viene portata al suo minimo o al suo massimo, mai nel mezzo. Questo è un risultato fondamentale della programmazione lineare.
Con l'utilità logaritmica invece la soluzione è interna cioè ogni categoria riceve un'allocazione intermedia.
Implementazione in Julia
Innanzitutto installo le librerie di Julia che mi servono:
using Pkg
Pkg.add("JuMP")
Pkg.add("Ipopt")
Pkg.add("HiGHS")
Modello lineare
Si calcolano le variabili di spesa che massimizzano l'utilità soggette ai vari vincoli mediante la libreria HiGHS:
using JuMP, HiGHS
budget_totale = 3000.0 # € mensili
model = Model(HiGHS.Optimizer)
@variable(model,800 <= affitto <= 1000)
@variable(model,300 <= cibo <= 600)
@variable(model,100 <= trasporti <= 300)
@variable(model,0 <= svago <= 400)
@variable(model,100 <= risparmio <= 800)
@variable(model,0 <= vestiti <= 200)
@constraint(model, affitto + cibo + trasporti + svago + risparmio + vestiti <= budget_totale)
@objective(model, Max, 0.8*affitto +1.5*cibo +1.2*trasporti +2*svago + 1.8*risparmio +0.4*vestiti )
optimize!(model)
println("______________________________________________________________")
println("Affitto = ", value(affitto))
println("Cibo = ",value(cibo))
println("Trasporti = ",value(trasporti)),
println("Svago = ",value(svago))
println("Risparmio = ", value(risparmio))
println("Vestiti = ", value(vestiti))
Running HiGHS 1.13.1 (git hash: 1d267d97c): Copyright (c) 2026 under Apache 2.0 license terms Using BLAS: blastrampoline LP has 1 row; 6 cols; 6 nonzeros Coefficient ranges: Matrix [1e+00, 1e+00] Cost [4e-01, 2e+00] Bound [1e+02, 1e+03] RHS [3e+03, 3e+03] Presolving model 1 rows, 1 cols, 1 nonzeros 0s 0 rows, 0 cols, 0 nonzeros 0s Presolve reductions: rows 0(-1); columns 0(-6); nonzeros 0(-6) - Reduced to empty Performed postsolve Solving the original LP from the solution after postsolve Model status : Optimal Objective value : 4.2200000000e+03 P-D objective error : 0.0000000000e+00 HiGHS run time : 0.00 ______________________________________________________________ Affitto = 900.0 Cibo = 600.0 Trasporti = 300.0 Svago = 400.0 Risparmio = 800.0 Vestiti = 0.0
Questi valori massimizzano la funzione di utilità soggetta ai vincoli.
Modello non lineare
Si calcolano le variabili di spesa che massimizzano l'utilità logaritmica soggette ai vari vincoli mediante la libreria Ipopt:
using JuMP, Ipopt
budget_totale = 3000.0 # € mensili
model_nl = Model(Ipopt.Optimizer)
set_optimizer_attribute(model_nl, "print_level", 0)
@variable(model_nl,800 <= affitto <= 1000)
@variable(model_nl,300 <= cibo <= 600)
@variable(model_nl,100 <= trasporti <= 300)
@variable(model_nl,0 <= svago <= 400)
@variable(model_nl,100 <= risparmio <= 800)
@variable(model_nl,0 <= vestiti <= 200)
@constraint(model_nl, affitto + cibo + trasporti + svago + risparmio + vestiti <= budget_totale)
# Utilità logaritmica: U(x) = w_i * log(x_i)
@objective(model_nl, Max, 0.8*log(affitto) +1.5*log(cibo) +1.2*log(trasporti) +2*log(svago) + 1.8*log(risparmio) +0.4*log(vestiti) )
optimize!(model_nl)
println("Affitto = ", value(affitto))
println("Cibo = ",value(cibo))
println("Trasporti = ",value(trasporti)),
println("Svago = ",value(svago))
println("Risparmio = ", value(risparmio))
println("Vestiti = ", value(vestiti))
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit https://github.com/coin-or/Ipopt
******************************************************************************
Affitto = 800.0086863353699
Cibo = 599.4405027557945
Trasporti = 299.9919466163567
Svago = 399.9950988314647
Risparmio = 736.8257493821642
Vestiti = 163.7329107226028
Questi valori massimizzano la funzione di utilità soggetta ai vincoli.