From 85c2d38e2c0616da11ce398a90716026dc84013b Mon Sep 17 00:00:00 2001 From: FiveMovesAhead Date: Fri, 17 Oct 2025 14:01:20 +0100 Subject: [PATCH] Submitted knapsack/knap_one --- .../src/knapsack/knap_one/README.md | 23 +++ tig-algorithms/src/knapsack/knap_one/mod.rs | 193 ++++++++++++++++++ tig-algorithms/src/knapsack/mod.rs | 3 +- 3 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 tig-algorithms/src/knapsack/knap_one/README.md create mode 100644 tig-algorithms/src/knapsack/knap_one/mod.rs diff --git a/tig-algorithms/src/knapsack/knap_one/README.md b/tig-algorithms/src/knapsack/knap_one/README.md new file mode 100644 index 0000000..62a3b27 --- /dev/null +++ b/tig-algorithms/src/knapsack/knap_one/README.md @@ -0,0 +1,23 @@ +# TIG Code Submission + + ## Submission Details + + * **Challenge Name:** knapsack + * **Submission Name:** knap_one + * **Copyright:** 2024 VNX + * **Identity of Submitter:** VNX + * **Identity of Creator of Algorithmic Method:** null + * **Unique Algorithm Identifier (UAI):** null + + ## License + + The files in this folder are under the following licenses: + * TIG Benchmarker Outbound License + * TIG Commercial License + * TIG Inbound Game License + * TIG Innovator Outbound Game License + * TIG Open Data License + * TIG THV Game License + + Copies of the licenses can be obtained at: + https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses \ No newline at end of file diff --git a/tig-algorithms/src/knapsack/knap_one/mod.rs b/tig-algorithms/src/knapsack/knap_one/mod.rs new file mode 100644 index 0000000..7222691 --- /dev/null +++ b/tig-algorithms/src/knapsack/knap_one/mod.rs @@ -0,0 +1,193 @@ +use anyhow::{anyhow, Result}; +use serde_json::{Map, Value}; +use tig_challenges::knapsack::*; + + +pub fn solve_challenge( + challenge: &Challenge, + save_solution: &dyn Fn(&Solution) -> Result<()>, + hyperparameters: &Option>, +) -> Result<()> { + Err(anyhow!("This algorithm is no longer compatible.")) +} + +// Old code that is no longer compatible +#[cfg(none)] +mod dead_code { + use anyhow::Result; + use tig_challenges::knapsack::*; + + pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result> { + let mut solution = Solution { + sub_solutions: Vec::new(), + }; + for sub_instance in &challenge.sub_instances { + match solve_sub_instance(sub_instance)? { + Some(sub_solution) => solution.sub_solutions.push(sub_solution), + None => return Ok(None), + } + } + Ok(Some(solution)) + } + + pub fn solve_sub_instance(challenge: &SubInstance) -> Result> { + const WAIT_ITERATIONS: usize = 5; + const MAX_STAGNANT_ITERATIONS: usize = 5; + + let num_items = challenge.weights.len(); + let mut selected_items = vec![false; num_items]; + let mut total_value: i32 = 0; + let mut total_weight: u32 = 0; + let mut wait_map = vec![None; num_items]; + let values: Vec = challenge.values.iter().map(|&v| v as i32).collect(); + let weights: Vec = challenge.weights.iter().map(|&w| w as f64).collect(); + + let mut items_by_ratio: Vec<(usize, f64)> = (0..num_items) + .map(|i| { + let adjusted_value = values[i]; + let ratio = adjusted_value as f64 / weights[i]; + (i, ratio) + }) + .collect(); + items_by_ratio.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); + let mut interaction_gains = vec![0; num_items]; + + let mut iteration_count = 0; + let mut stagnant_iterations = 0; + let mut max_total_value = total_value; + + loop { + iteration_count += 1; + + for entry in &mut wait_map { + if let Some(iter) = entry { + if *iter <= iteration_count { + *entry = None; + } + } + } + + let mut available_items: Vec<_> = items_by_ratio + .iter() + .filter(|(i, _)| !selected_items[*i] && wait_map[*i].is_none()) + .collect(); + + let mut improvement_found = false; + let mut index = 0; + + while index < available_items.len() { + let (i, _) = available_items[index]; + let individual_value = values[*i]; + let interaction_gain = interaction_gains[*i]; + let gain = individual_value + interaction_gain; + if gain >= individual_value { + selected_items[*i] = true; + total_value += gain; + total_weight += challenge.weights[*i]; + + for j in 0..num_items { + interaction_gains[j] += challenge.interaction_values[*i][j]; + } + + improvement_found = true; + available_items.remove(index); + } else { + index += 1; + } + } + + if !improvement_found { + for &(i, _) in &available_items { + let new_item_value = values[*i] + interaction_gains[*i]; + let new_item_weight = challenge.weights[*i]; + + if new_item_value <= values[*i] { + continue; + } + + for j in 0..num_items { + if selected_items[j] { + let removal_loss = values[j] + interaction_gains[j]; + if total_value + new_item_value - removal_loss > total_value { + for k in 0..num_items { + interaction_gains[k] -= challenge.interaction_values[j][k]; + } + selected_items[j] = false; + total_value -= removal_loss; + total_weight -= challenge.weights[j]; + + selected_items[*i] = true; + total_value += new_item_value; + total_weight += new_item_weight; + + for k in 0..num_items { + interaction_gains[k] += challenge.interaction_values[*i][k]; + } + + wait_map[j] = Some(iteration_count + WAIT_ITERATIONS); + improvement_found = true; + break; + } + } + } + + if improvement_found { + break; + } else { + return Ok(None); + } + } + } + + if total_weight > challenge.max_weight { + let mut item_loss_ratios = Vec::new(); + for i in 0..num_items { + if selected_items[i] { + let loss = values[i] + interaction_gains[i]; + let ratio = weights[i] / (loss as f64).max(1.0); + item_loss_ratios.push((ratio, i)); + } + } + item_loss_ratios.sort_unstable_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + + while total_weight > challenge.max_weight { + if let Some((_, item)) = item_loss_ratios.pop() { + for k in 0..num_items { + interaction_gains[k] -= challenge.interaction_values[item][k]; + } + selected_items[item] = false; + total_weight -= challenge.weights[item]; + total_value -= values[item] + interaction_gains[item]; + wait_map[item] = Some(iteration_count + WAIT_ITERATIONS); + } else { + break; + } + } + } + + if total_value >= challenge.baseline_value as i32 && total_weight <= challenge.max_weight { + let result_items: Vec = selected_items + .iter() + .enumerate() + .filter(|&(_, &is_selected)| is_selected) + .map(|(i, _)| i) + .collect(); + + return Ok(Some(SubSolution { + items: result_items, + })); + } + + if total_value > max_total_value { + max_total_value = total_value; + stagnant_iterations = 0; + } else { + stagnant_iterations += 1; + } + + if stagnant_iterations >= MAX_STAGNANT_ITERATIONS { + return Ok(None); + } + } + } +} \ No newline at end of file diff --git a/tig-algorithms/src/knapsack/mod.rs b/tig-algorithms/src/knapsack/mod.rs index 33ddf59..1d24c78 100644 --- a/tig-algorithms/src/knapsack/mod.rs +++ b/tig-algorithms/src/knapsack/mod.rs @@ -116,7 +116,8 @@ // c003_a059 -// c003_a060 +pub mod knap_one; +pub use knap_one as c003_a060; // c003_a061