From f1384f93b85968689b95d18d11f7fcaed673ca82 Mon Sep 17 00:00:00 2001 From: Malte Voos Date: Mon, 21 Mar 2022 16:27:58 +0100 Subject: bonusaufgabe erster ansatz --- bonusaufgabe/src/main.rs | 304 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 bonusaufgabe/src/main.rs (limited to 'bonusaufgabe/src') diff --git a/bonusaufgabe/src/main.rs b/bonusaufgabe/src/main.rs new file mode 100644 index 0000000..f3a0301 --- /dev/null +++ b/bonusaufgabe/src/main.rs @@ -0,0 +1,304 @@ +use bitvec::prelude::*; +use std::borrow::Borrow; +use std::env; +use std::fmt; +use std::fs; +use std::marker::PhantomData; +use std::mem; +use std::ops::BitXor; +use std::path::Display; +use std::process; + +fn main() { + let task_file_name = match env::args().nth(1) { + Some(x) => x, + None => { + eprintln!("Nutzung: bonusaufgabe "); + process::exit(1); + } + }; + let task_str = fs::read_to_string(task_file_name).expect("Datei kann nicht gelesen werden"); + let task = Task::try_from(task_str.as_str()).expect("Datei enthält keine gültige Aufgabe"); + + match solve_task(task) { + Some(solution) => println!("{}", solution), + None => eprintln!("Keine Lösung gefunden"), + } +} + +#[derive(Clone)] +struct Card(Vec); + +struct Task { + cards: Vec, + num_pass_cards: usize, + bits_per_card: usize, +} + +struct Solution { + real_cards: Vec, +} + +fn solve_task(task: Task) -> Option { + let Task { + cards, + num_pass_cards, + bits_per_card, + } = task; + let num_cards = cards.len(); + let num_real_cards = num_pass_cards + 1; + + let mut matrix: Vec = vec![BitVec::with_capacity(num_cards); bits_per_card]; + for card in cards.iter() { + for (bit_idx, bit) in card.0.iter().enumerate() { + matrix[bit_idx].push(*bit); + } + } + + let mut free_vars = Vec::new(); + let mut basic_vars = Vec::new(); + + let mut current_row = 0; + let mut current_col = 0; + while current_row < bits_per_card && current_col < num_cards { + let pivot_row = match (current_row..bits_per_card).find(|row| matrix[*row][current_col]) { + Some(row) => row, + None => { + free_vars.push(current_col); + current_col += 1; + continue; + } + }; + matrix.swap(current_row, pivot_row); + basic_vars.push((current_row, current_col)); + for lower_row in (current_row + 1)..bits_per_card { + if matrix[lower_row][current_col] { + let current_row_cloned = matrix[current_row].clone(); + matrix[lower_row] ^= current_row_cloned; + } + } + current_row += 1; + current_col += 1; + } + free_vars.extend(current_col..num_cards); + + let num_basic_vars = basic_vars.len(); + let num_free_vars = free_vars.len(); + + // Sanity Check: Nach dem Rangsatz immer erfüllt + assert_eq!(num_basic_vars + num_free_vars, num_cards); + + for (pivot_row, pivot_col) in basic_vars.iter().rev() { + for upper_row in (0..*pivot_row).rev() { + if matrix[upper_row][*pivot_col] { + let pivot_row_cloned = matrix[*pivot_row].clone(); + matrix[upper_row] ^= pivot_row_cloned; + } + } + } + + print_matrix(&matrix); + + let basic_vars_terms = basic_vars + .iter() + .map(|(basic_var_row, _basic_var_col)| { + free_vars + .iter() + .map(|free_var| matrix[*basic_var_row][*free_var]) + .collect::() + }) + .collect::>(); + + println!("num_real_cards {}", num_real_cards); + println!("num_cards {}", num_cards); + println!("num_free_vars {}", num_free_vars); + println!("num_basic_vars {}", num_basic_vars); + + // std::process::exit(0); + + let mut solution = None; + + 'outer: for num_ones_in_free_vars in 0..=(num_free_vars.min(num_real_cards)) { + let mut iterator = BitSubsetIterator::new(num_free_vars, num_ones_in_free_vars); + while let Some(free_var_values) = iterator.next() { + // print!("trying "); + // for b in free_var_values { + // if *b { + // print!("1"); + // } else { + // print!("0"); + // } + // } + // println!(""); + + let basic_var_values = basic_vars_terms + .iter() + .map(|basic_var_term| { + let basic_var_solution_term = basic_var_term.clone() & free_var_values; + let basic_var_solution = basic_var_solution_term + .iter() + .fold(false, |acc, bit| acc ^ *bit); + basic_var_solution + }) + .collect::(); + let num_ones_in_basic_vars = basic_var_values + .iter() + .filter(|solution_bit| **solution_bit) + .count(); + let num_ones_in_solution = num_ones_in_free_vars + num_ones_in_basic_vars; + + if num_ones_in_solution == num_real_cards { + let mut solution_vector = BitVec::::repeat(false, num_cards); + + for (free_var_idx, free_var_val) in free_vars.iter().zip(free_var_values.iter()) { + solution_vector.set(*free_var_idx, *free_var_val); + } + for ((_, basic_var_idx), basic_var_val) in + basic_vars.iter().zip(basic_var_values.iter()) + { + solution_vector.set(*basic_var_idx, *basic_var_val); + } + + assert_eq!(solution_vector.count_ones(), num_real_cards); + //TODO: more sanity checks + + print!("solution free vars "); + for b in free_var_values { + if *b { + print!("1"); + } else { + print!("0"); + } + } + println!(""); + + solution = Some(Solution { + real_cards: solution_vector + .into_iter() + .enumerate() + .filter(|(_card_idx, is_real)| *is_real) + .map(|(real_card_idx, _)| (cards[real_card_idx]).clone()) + .collect(), + }); + + break 'outer; + } + } + } + + solution +} + +struct BitSubsetIterator { + fresh: bool, + state: BitVec, +} + +impl BitSubsetIterator { + fn new(set_size: usize, subset_size: usize) -> Self { + let mut initial_state = BitVec::repeat(false, set_size); + initial_state.get_mut(0..subset_size).unwrap().fill(true); + + Self { + fresh: true, + state: initial_state, + } + } + + fn next(&mut self) -> Option<&BitSlice> { + if self.fresh { + self.fresh = false; + Some(self.state.borrow()) + } else { + self.state + .iter_ones() + .enumerate() + .find( + |(_num_prev_ones, one_idx)| match self.state.get(*one_idx + 1) { + Some(bit) => !bit, + None => false, + }, + ) + .map(|(num_prev_ones, moveable_one_idx)| { + self.state.set(moveable_one_idx, false); + self.state.set(moveable_one_idx + 1, true); + self.state.get_mut(0..num_prev_ones).unwrap().fill(true); + self.state + .get_mut(num_prev_ones..moveable_one_idx) + .unwrap() + .fill(false); + self.state.borrow() + }) + } + } +} + +fn print_matrix(matrix: &[BitVec]) { + for row in matrix { + for col in row { + if *col { + print!("1"); + } else { + print!("0"); + } + } + println!(""); + } +} + +impl TryFrom<&str> for Task { + type Error = (); + + fn try_from(value: &str) -> Result { + let mut lines = value.lines(); + let first_line = lines.next().ok_or(())?; + let mut first_line_words = first_line.split_ascii_whitespace(); + + let total_num_cards_str = first_line_words.next().ok_or(())?; + let total_num_cards = str::parse::(total_num_cards_str).map_err(|_| ())?; + let num_pass_cards_str = first_line_words.next().ok_or(())?; + let num_pass_cards = str::parse::(num_pass_cards_str).map_err(|_| ())?; + let bits_per_card_str = first_line_words.next().ok_or(())?; + let bits_per_card = str::parse::(bits_per_card_str).map_err(|_| ())?; + + let cards = lines + .into_iter() + .map(|line| { + Card( + line.chars() + .flat_map(|char| match char { + '0' => Some(false), + '1' => Some(true), + _ => None, + }) + .collect::>(), + ) + }) + .collect::>(); + + if cards.len() != total_num_cards { + return Err(()); + } + + Ok(Task { + cards, + num_pass_cards, + bits_per_card, + }) + } +} + +impl fmt::Display for Solution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for card in self.real_cards.iter() { + for bit in card.0.iter() { + match bit { + true => write!(f, "1")?, + false => write!(f, "0")?, + }; + } + writeln!(f, "")?; + } + Ok(()) + } +} -- cgit 1.4.1