struct Simplex { tableau: Vec>, // シンプレックス表 m: usize, // 制約式の数 n: usize, // 変数の数 } impl Simplex { // A: 制約行列, b: 右辺定数ベクトル, c: 目的関数の係数ベクトル // offset: 目的関数の定数項 fn new(a: Vec>, b: Vec, c: Vec, offset: f64) -> Self { let m = a.len(); let n = c.len(); // 表のサイズ: (行: m + 1) x (列: n + m + 1) // 列構成: [変数x | スラック変数s | 右辺RHS] let mut tableau = vec![vec![0.0; n + m + 1]; m + 1]; for i in 0..m { for j in 0..n { tableau[i][j] = a[i][j]; } tableau[i][n + i] = 1.0; // スラック変数の係数 tableau[i][n + m] = b[i]; // RHS } for j in 0..n { tableau[m][j] = -c[j]; // 目的関数 (最大化のため符号反転) } tableau[m][n + m] = offset; // 定数項をRHSの初期値にセット Simplex { tableau, m, n } } fn solve(&mut self) -> Result { loop { // 1. ピボット列の選択 (目的関数行で最も負の要素) let mut pivot_col = 0; let mut min_val = 0.0; for j in 0..(self.n + self.m) { if self.tableau[self.m][j] < min_val { min_val = self.tableau[self.m][j]; pivot_col = j; } } // 最適性の判定: 負の係数がなければ終了 if min_val >= -1e-9 { break; } // 2. ピボット行の選択 (最小比テスト) let mut pivot_row = None; let mut min_ratio = f64::INFINITY; for i in 0..self.m { if self.tableau[i][pivot_col] > 1e-9 { let ratio = self.tableau[i][self.n + self.m] / self.tableau[i][pivot_col]; if ratio < min_ratio { min_ratio = ratio; pivot_row = Some(i); } } } let p_row = match pivot_row { Some(r) => r, None => return Err("問題は非有界(Unbounded)です。".to_string()), }; // 3. ピボット操作 (ガウスの消去法) self.pivot(p_row, pivot_col); } Ok(self.tableau[self.m][self.n + self.m]) } fn pivot(&mut self, row: usize, col: usize) { let divisor = self.tableau[row][col]; for j in 0..=(self.n + self.m) { self.tableau[row][j] /= divisor; } for i in 0..=self.m { if i != row { let multiplier = self.tableau[i][col]; for j in 0..=(self.n + self.m) { self.tableau[i][j] -= multiplier * self.tableau[row][j]; } } } } fn print_tableau(&self) { println!("--- Tableau ---"); for row in &self.tableau { for val in row { print!("{:>8.2} ", val); } println!(); } } } fn main() { println!("Solving 0-1 Integer Programming Problem:"); println!("Maximize: Z = 3x1 + 4x2 + x3 + 2x4"); println!("Subject to: 2x1 + 3x2 + x3 + 3x4 <= 4"); println!("x_i in {{0, 1}} for i in {{1, 2, 3, 4}}\n"); let c = vec![3.0, 4.0, 1.0, 2.0]; // 係数 (x1, x2, x3, x4) let a = vec![2.0, 3.0, 1.0, 3.0]; // 制約の係数 let b = 4.0; // 制約の右辺 // 1. 0-1 整数計画問題として解く (全探索) let mut max_z_int = -1.0; let mut best_x_int = vec![0; 4]; for i in 0..(1 << 4) { let mut current_z = 0.0; let mut current_weight = 0.0; let mut x = vec![0; 4]; for j in 0..4 { if (i >> j) & 1 == 1 { current_z += c[j]; current_weight += a[j]; x[j] = 1; } } if current_weight <= b { if current_z > max_z_int { max_z_int = current_z; best_x_int = x; } } } println!("--- 0-1 Integer Solution ---"); println!("Optimal Z: {:.1}", max_z_int); for (i, val) in best_x_int.iter().enumerate() { println!("x{} = {}", i + 1, val); } println!(); // 2. 線形緩和問題 (Continuous Relaxation) をシンプレックス法で解く println!("--- Continuous Relaxation (Simplex Method with xi <= 1) ---"); let a_matrix = vec![ vec![2.0, 3.0, 1.0, 3.0], // 主制約 vec![1.0, 0.0, 0.0, 0.0], // x1 <= 1 vec![0.0, 1.0, 0.0, 0.0], // x2 <= 1 vec![0.0, 0.0, 1.0, 0.0], // x3 <= 1 vec![0.0, 0.0, 0.0, 1.0], // x4 <= 1 ]; let b_vec = vec![4.0, 1.0, 1.0, 1.0, 1.0]; let c_vec = vec![3.0, 4.0, 1.0, 2.0]; let offset = 0.0; let mut simplex = Simplex::new(a_matrix, b_vec, c_vec, offset); match simplex.solve() { Ok(res) => { println!("Optimal Z (Upper Bound): {:.4}", res); println!("\nFinal Tableau for Relaxation:"); simplex.print_tableau(); } Err(e) => println!("Error: {}", e), } }