product_mix/
product-mix.rs1#![allow(unused)]
2
3use std::{collections::HashMap, time::Instant};
4use good_lp::{
5 constraint, default_solver, variable, variables, Expression, Solution, SolverModel
6};
7
8fn main() {
9 let start_time = Instant::now();
11
12 engine::init();
14
15 println!("Balance Engine - Production Mix Optimization Demo");
16
17 let raw_materials = vec!["A", "B", "C"];
19 let products = vec!["Super", "Unleaded", "Super_Unleaded"];
20
21 let mut octane_number = HashMap::new();
23 octane_number.insert("A", 120.0);
24 octane_number.insert("B", 90.0);
25 octane_number.insert("C", 130.0);
26
27 let mut material_cost = HashMap::new();
28 material_cost.insert("A", 38.0);
29 material_cost.insert("B", 42.0);
30 material_cost.insert("C", 105.0);
31
32 let mut max_available = HashMap::new();
33 max_available.insert("A", 1000.0);
34 max_available.insert("B", 1200.0);
35 max_available.insert("C", 700.0);
36
37 let mut octane_requirement = HashMap::new();
39 octane_requirement.insert("Super", 94.0);
40 octane_requirement.insert("Unleaded", 92.0);
41 octane_requirement.insert("Super_Unleaded", 96.0);
42
43 let mut selling_price = HashMap::new();
44 selling_price.insert("Super", 85.0);
45 selling_price.insert("Unleaded", 80.0);
46 selling_price.insert("Super_Unleaded", 88.0);
47
48 let mut demand = HashMap::new();
49 demand.insert("Super", 800.0);
50 demand.insert("Unleaded", 1100.0);
51 demand.insert("Super_Unleaded", 500.0);
52
53 let mut vars = variables!();
55
56 let mut z = HashMap::new();
58 for &i in &raw_materials {
59 for &j in &products {
60 z.insert((i, j), vars.add(variable().min(0.0).name(format!("z_{}_{}", i, j))));
61 }
62 }
63
64 let mut y = HashMap::new();
66 for &j in &products {
67 y.insert(j, vars.add(variable().min(0.0).max(*demand.get(j).unwrap()).name(format!("y_{}", j))));
68 }
69
70 let mut objective = Expression::from(0.0);
72
73 for &j in &products {
75 objective += *selling_price.get(j).unwrap() * *y.get(j).unwrap();
76 }
77
78 for &i in &raw_materials {
80 for &j in &products {
81 objective -= *material_cost.get(i).unwrap() * *z.get(&(i, j)).unwrap();
82 }
83 }
84
85 let mut model = vars.maximise(objective.clone()).using(default_solver);
87
88 for &i in &raw_materials {
92 let mut usage = Expression::from(0.0);
93 for &j in &products {
94 usage += z.get(&(i, j)).unwrap();
95 }
96 model = model.with(constraint!(usage <= *max_available.get(i).unwrap()));
97 }
98
99 for &j in &products {
101 let mut sum_materials = Expression::from(0.0);
102 for &i in &raw_materials {
103 sum_materials += z.get(&(i, j)).unwrap();
104 }
105 model = model.with(constraint!(sum_materials == y.get(j).unwrap()));
106 }
107
108 for &j in &products {
110 let mut weighted_octane = Expression::from(0.0);
111 for &i in &raw_materials {
112 weighted_octane += *octane_number.get(i).unwrap() * *z.get(&(i, j)).unwrap();
113 }
114 let octane_req = *octane_requirement.get(j).unwrap() * *y.get(j).unwrap();
115 model = model.with(constraint!(weighted_octane >= octane_req));
116 }
117
118 match model.solve() {
120 Ok(solution) => {
121 println!("\nOptimal Solution Found:");
122 println!("Total Profit: €{:.2}", solution.eval(&objective));
123
124 println!("\nProduction Quantities:");
126 for &j in &products {
127 let amount = solution.value(*y.get(j).unwrap());
128 println!("{}: {:.2} tons (Max demand: {} tons)", j, amount, demand.get(j).unwrap());
129 }
130
131 println!("\nRaw Material Usage:");
133 for &i in &raw_materials {
134 let mut total_used = 0.0;
135 for &j in &products {
136 total_used += solution.value(*z.get(&(i, j)).unwrap());
137 }
138 let utilization = total_used / max_available.get(i).unwrap() * 100.0;
139 println!("{}: {:.2} tons ({:.1}% of available {} tons)",
140 i, total_used, utilization, max_available.get(i).unwrap());
141 }
142
143 println!("\nProduct Composition:");
145 for &j in &products {
146 println!("\n{} Mix:", j);
147 let total_product = solution.value(*y.get(j).unwrap());
148 if total_product > 0.001 { for &i in &raw_materials {
150 let tons_used = solution.value(*z.get(&(i, j)).unwrap());
151 let percentage = (tons_used / total_product) * 100.0;
152 println!(" {}: {:.1}% ({:.2} tons)", i, percentage, tons_used);
153 }
154 } else {
155 println!(" Not produced");
156 }
157 }
158
159 println!("\nOctane Verification:");
161 for &j in &products {
162 let total_product = solution.value(*y.get(j).unwrap());
163 if total_product > 0.001 { let mut weighted_octane_sum = 0.0;
165 for &i in &raw_materials {
166 weighted_octane_sum += octane_number.get(i).unwrap() * solution.value(*z.get(&(i, j)).unwrap());
167 }
168 let achieved_octane = weighted_octane_sum / total_product;
169 println!("{}: Requirement = {}, Achieved = {:.2}",
170 j, octane_requirement.get(j).unwrap(), achieved_octane);
171 }
172 }
173
174 },
175 Err(e) => {
176 println!("No optimal solution found. Error: {:?}", e);
177 }
178 }
179
180 let elapsed = start_time.elapsed();
182 println!("\nTime elapsed: {:?}", elapsed);
183}