fn one_step_search()

in src/dachshund/beam.rs [149:234]


    fn one_step_search(
        &mut self,
        num_to_search: usize,
        beam_size: usize,
    ) -> CLQResult<(Candidate<'a, TGraph>, bool)> {
        let mut scored_expansion_candidates: HashSet<Candidate<TGraph>> = HashSet::new();
        let mut new_candidates: Vec<Candidate<TGraph>> = Vec::new();
        let mut can_continue: bool = false;
        // A map from a checksum to a reference to a candidate from the previous generation.
        // Used as a hint when materializing the neighborhood for the next generation of candidates.
        let mut previous_candidates = HashMap::new();

        for candidate in &self.candidates {
            if self.verbose {
                eprintln!(
                    "Considering the following candidate (score = {}, hash={}):\n{}",
                    match candidate.get_score() {
                        Ok(n) => n.to_string(),
                        Err(_) => "No score".to_string(),
                    },
                    candidate,
                    candidate.to_printable_row(self.non_core_types)?,
                );
            }
            if !self
                .visited_candidates
                .contains(&candidate.checksum.unwrap())
            {
                can_continue = true;
                let v: Vec<Candidate<TGraph>> = candidate.one_step_search(
                    num_to_search,
                    &mut self.visited_candidates,
                    &self.scorer,
                )?;
                if self.verbose {
                    eprintln!("Have {} visited candidates:", self.visited_candidates.len());
                    eprintln!("Found the following expansion candidates:");
                }
                for ell in v {
                    if self.verbose {
                        eprintln!(
                            "(score = {}): {}",
                            ell.get_score()?,
                            ell.to_printable_row(self.non_core_types)?,
                        );
                    }
                    scored_expansion_candidates.insert(ell);
                }
            }
            previous_candidates.insert(candidate.checksum.unwrap(), candidate);
            scored_expansion_candidates.insert(candidate.replicate(true));
        }

        // sort by score, with node_id as tie breaker for deterministic behaviour
        let mut v: Vec<Candidate<TGraph>> = scored_expansion_candidates.into_iter().collect();

        let mut bad_sort = false;
        v.sort_by(|a, b| {
            if let (Ok(a_score), Ok(b_score)) = (a.get_score(), b.get_score()) {
                let key_a = (a_score, a.checksum);
                let key_b = (b_score, b.checksum);
                if let Some(comparison) = key_a.partial_cmp(&key_b) {
                    return comparison.reverse();
                }
            }
            bad_sort = true;
            std::cmp::Ordering::Equal
        });
        if bad_sort {
            return Err(CLQError::new(
                "Failed to sort at least one unscored candidate.",
            ));
        }

        if self.verbose {
            eprintln!("Beam now contains:");
        }
        for mut ell in v {
            if new_candidates.len() < beam_size {
                ell.set_neigbhorhood_with_hint(&previous_candidates);
                new_candidates.push(ell);
            }
        }
        self.candidates = new_candidates;
        Ok((self.candidates[0].replicate(true), can_continue))
    }