Calcoli scientifici con Julia/Ottimizzazione del budget personale

Da testwiki.
Vai alla navigazione Vai alla ricerca

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 :

maxxU=∑i=1nwixis.t.∑i=1nxi≤Bxi≥mi∀ixi≤Mi∀i

quello non lineare:

maxxU=∑i=1nwilog(xi)s.t.∑i=1nxi≤Bxi≥mi∀ixi≤Mi∀i

dove:

  • xi∈ℝ+ è la spesa allocata alla categoria i
  • wi>0 è il peso (importanza relativa) della categoria i
  • B>0 è il budget totale disponibile
  • mi≥0 è la spesa minima obbligatoria per la categoria i
  • Mi>mi è la spesa massima ammissibile per la categoria i


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:

U=w1log(x1)+w2log(x2)+…+wnlog(xn) con i relativi vincoli di bilancio del tipo :

nel modello lineare invece si massimizza :

U=w1x1+w2x2+…+wnxn

con :

mi≤xi≤Mi e ∑i=1nxi≤B

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:

xi∗=wi⋅B∑j=1nwj

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.

Template:Avanzamento