mirror of
https://github.com/tig-pool-nk/tig-monorepo.git
synced 2026-02-27 15:37:21 +08:00
Update knapsack to QKP with negative interaction values
This commit is contained in:
parent
6ae5d622af
commit
bf87fb7928
@ -52,6 +52,7 @@ pub struct Challenge {
|
||||
pub difficulty: Difficulty,
|
||||
pub weights: Vec<u32>,
|
||||
pub values: Vec<u32>,
|
||||
pub interaction_values: Vec<Vec<i32>>,
|
||||
pub max_weight: u32,
|
||||
pub min_value: u32,
|
||||
}
|
||||
@ -75,32 +76,57 @@ impl crate::ChallengeTrait<Solution, Difficulty, 2> for Challenge {
|
||||
fn generate_instance(seeds: [u64; 8], difficulty: &Difficulty) -> Result<Challenge> {
|
||||
let mut rngs = RngArray::new(seeds);
|
||||
|
||||
// Generate weights w_i in the range [1, 50]
|
||||
let weights: Vec<u32> = (0..difficulty.num_items)
|
||||
.map(|_| rngs.get_mut().gen_range(1..50))
|
||||
.map(|_| rngs.get_mut().gen_range(1..=50))
|
||||
.collect();
|
||||
// Generate values v_i in the range [50, 100]
|
||||
let values: Vec<u32> = (0..difficulty.num_items)
|
||||
.map(|_| rngs.get_mut().gen_range(1..50))
|
||||
.map(|_| rngs.get_mut().gen_range(50..=100))
|
||||
.collect();
|
||||
|
||||
// Generate interactive values V_ij in the range [1, 50], with V_ij == V_ji and V_ij where i==j is 0.
|
||||
let mut interaction_values: Vec<Vec<i32>> = vec![vec![0; difficulty.num_items]; difficulty.num_items];
|
||||
for i in 0..difficulty.num_items {
|
||||
for j in (i + 1)..difficulty.num_items {
|
||||
let value = rngs.get_mut().gen_range(-50..=50);
|
||||
interaction_values[i][j] = value;
|
||||
interaction_values[j][i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
let max_weight: u32 = weights.iter().sum::<u32>() / 2;
|
||||
|
||||
// Baseline greedy algorithm
|
||||
let mut sorted_value_to_weight_ratio: Vec<usize> = (0..difficulty.num_items).collect();
|
||||
sorted_value_to_weight_ratio.sort_by(|&a, &b| {
|
||||
let ratio_a = values[a] as f64 / weights[a] as f64;
|
||||
let ratio_b = values[b] as f64 / weights[b] as f64;
|
||||
// Precompute the ratio between the total value (value + sum of interactive values) and
|
||||
// weight for each item. Pair the ratio with the item's weight and index
|
||||
let mut value_weight_ratios: Vec<(usize, f32, u32)> = (0..difficulty.num_items)
|
||||
.map(|i| {
|
||||
let tot_value = values[i] as i32 + interaction_values[i].iter().sum::<i32>();
|
||||
let weight = weights[i];
|
||||
let ratio = tot_value as f32 / weight as f32;
|
||||
(i, ratio, weight)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Sort the list of tuples by value-to-weight ratio in descending order
|
||||
value_weight_ratios.sort_unstable_by(|&(_, ratio_a, _), &(_, ratio_b, _)| {
|
||||
ratio_b.partial_cmp(&ratio_a).unwrap()
|
||||
});
|
||||
|
||||
let mut total_weight = 0;
|
||||
let mut min_value = 0;
|
||||
for &item in &sorted_value_to_weight_ratio {
|
||||
if total_weight + weights[item] > max_weight {
|
||||
continue;
|
||||
let mut selected_indices = Vec::new();
|
||||
for &(i, _, weight) in &value_weight_ratios {
|
||||
if total_weight + weight <= max_weight {
|
||||
selected_indices.push(i);
|
||||
total_weight += weight;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
min_value += values[item];
|
||||
total_weight += weights[item];
|
||||
}
|
||||
min_value = (min_value as f64 * (1.0 + difficulty.better_than_baseline as f64 / 1000.0))
|
||||
selected_indices.sort_unstable();
|
||||
|
||||
let mut min_value = calculate_total_value(&selected_indices, &values, &interaction_values);
|
||||
min_value = (min_value as f32 * (1.0 + difficulty.better_than_baseline as f32 / 1000.0))
|
||||
.round() as u32;
|
||||
|
||||
Ok(Challenge {
|
||||
@ -108,6 +134,7 @@ impl crate::ChallengeTrait<Solution, Difficulty, 2> for Challenge {
|
||||
difficulty: difficulty.clone(),
|
||||
weights,
|
||||
values,
|
||||
interaction_values,
|
||||
max_weight,
|
||||
min_value,
|
||||
})
|
||||
@ -118,17 +145,18 @@ impl crate::ChallengeTrait<Solution, Difficulty, 2> for Challenge {
|
||||
if selected_items.len() != solution.items.len() {
|
||||
return Err(anyhow!("Duplicate items selected."));
|
||||
}
|
||||
if let Some(item) = selected_items
|
||||
.iter()
|
||||
.find(|&&item| item >= self.weights.len())
|
||||
{
|
||||
return Err(anyhow!("Item ({}) is out of bounds", item));
|
||||
}
|
||||
|
||||
let total_weight = selected_items
|
||||
.iter()
|
||||
.map(|&item| self.weights[item])
|
||||
.map(|&item| {
|
||||
if item >= self.weights.len() {
|
||||
return Err(anyhow!("Item ({}) is out of bounds", item));
|
||||
}
|
||||
Ok(self.weights[item])
|
||||
}).collect::<Result<Vec<_>, _>>()?
|
||||
.iter()
|
||||
.sum::<u32>();
|
||||
|
||||
if total_weight > self.max_weight {
|
||||
return Err(anyhow!(
|
||||
"Total weight ({}) exceeded max weight ({})",
|
||||
@ -136,10 +164,8 @@ impl crate::ChallengeTrait<Solution, Difficulty, 2> for Challenge {
|
||||
self.max_weight
|
||||
));
|
||||
}
|
||||
let total_value = selected_items
|
||||
.iter()
|
||||
.map(|&item| self.values[item])
|
||||
.sum::<u32>();
|
||||
let selected_items_vec : Vec<usize> = selected_items.into_iter().collect();
|
||||
let total_value = calculate_total_value(&selected_items_vec, &self.values, &self.interaction_values);
|
||||
if total_value < self.min_value {
|
||||
Err(anyhow!(
|
||||
"Total value ({}) does not reach minimum value ({})",
|
||||
@ -151,3 +177,29 @@ impl crate::ChallengeTrait<Solution, Difficulty, 2> for Challenge {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_total_value(indices: &Vec<usize>, values: &Vec<u32>, interaction_values: &Vec<Vec<i32>>) -> u32 {
|
||||
let mut indices = indices.clone();
|
||||
indices.sort_unstable();
|
||||
|
||||
let mut total_value = 0i32;
|
||||
|
||||
// Sum the individual values
|
||||
for &i in &indices {
|
||||
total_value += values[i] as i32;
|
||||
}
|
||||
|
||||
// Sum the interactive values for pairs in indices
|
||||
for i in 0..indices.len() {
|
||||
for j in (i + 1)..indices.len() {
|
||||
let idx_i = indices[i];
|
||||
let idx_j = indices[j];
|
||||
total_value += interaction_values[idx_i][idx_j];
|
||||
}
|
||||
}
|
||||
|
||||
match total_value {
|
||||
v if v < 0 => 0u32,
|
||||
v => v as u32
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user