// matrix_chain_multiply finds the minimum number of multiplications to perform a chain of matrix
// multiplications. The input matrices represents the dimensions of matrices. For example [1,2,3,4]
// represents matrices of dimension (1x2), (2x3), and (3x4)
//
// Lets say we are given [4, 3, 2, 1]. If we naively multiply left to right, we get:
//
// (4*3*2) + (4*2*1) = 20
//
// We can reduce the multiplications by reordering the matrix multiplications:
//
// (3*2*1) + (4*3*1) = 18
//
// We solve this problem with dynamic programming and tabulation. table[i][j] holds the optimal
// number of multiplications in range matrices[i..j] (inclusive). Note this means that table[i][i]
// and table[i][i+1] are always zero, since those represent a single vector/matrix and do not
// require any multiplications.
//
// For any i, j, and k = i+1, i+2, ..., j-1:
//
// table[i][j] = min(table[i][k] + table[k][j] + matrices[i] * matrices[k] * matrices[j])
//
// table[i][k] holds the optimal solution to matrices[i..k]
//
// table[k][j] holds the optimal solution to matrices[k..j]
//
// matrices[i] * matrices[k] * matrices[j] computes the number of multiplications to join the two
// matrices together.
//
// Runs in O(n^3) time and O(n^2) space.

pub fn matrix_chain_multiply(matrices: Vec<u32>) -> u32 {
    let n = matrices.len();
    if n <= 2 {
        // No multiplications required.
        return 0;
    }
    let mut table = vec![vec![0; n]; n];

    for length in 2..n {
        for i in 0..n - length {
            let j = i + length;
            table[i][j] = u32::MAX;
            for k in i + 1..j {
                let multiplications =
                    table[i][k] + table[k][j] + matrices[i] * matrices[k] * matrices[j];
                if multiplications < table[i][j] {
                    table[i][j] = multiplications;
                }
            }
        }
    }

    table[0][n - 1]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn basic() {
        assert_eq!(matrix_chain_multiply(vec![1, 2, 3, 4]), 18);
        assert_eq!(matrix_chain_multiply(vec![4, 3, 2, 1]), 18);
        assert_eq!(matrix_chain_multiply(vec![40, 20, 30, 10, 30]), 26000);
        assert_eq!(matrix_chain_multiply(vec![1, 2, 3, 4, 3]), 30);
        assert_eq!(matrix_chain_multiply(vec![1, 2, 3, 4, 3]), 30);
        assert_eq!(matrix_chain_multiply(vec![4, 10, 3, 12, 20, 7]), 1344);
    }

    #[test]
    fn zero() {
        assert_eq!(matrix_chain_multiply(vec![]), 0);
        assert_eq!(matrix_chain_multiply(vec![10]), 0);
        assert_eq!(matrix_chain_multiply(vec![10, 20]), 0);
    }
}


use std::cmp::max;
use std::cmp::min;

/// Maximal Square
///
/// Given an `m` * `n` binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.\
/// <https://leetcode.com/problems/maximal-square/>
///
/// # Arguments:
///   * `matrix` - an array of integer array
///
/// # Complexity
///   - time complexity: O(n^2),
///   - space complexity: O(n),
pub fn maximal_square(matrix: &mut [Vec<i32>]) -> i32 {
    if matrix.is_empty() {
        return 0;
    }

    let rows = matrix.len();
    let cols = matrix[0].len();
    let mut result: i32 = 0;

    for row in 0..rows {
        for col in 0..cols {
            if matrix[row][col] == 1 {
                if row == 0 || col == 0 {
                    result = max(result, 1);
                } else {
                    let temp = min(matrix[row - 1][col - 1], matrix[row - 1][col]);

                    let count: i32 = min(temp, matrix[row][col - 1]) + 1;
                    result = max(result, count);

                    matrix[row][col] = count;
                }
            }
        }
    }

    result * result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        assert_eq!(maximal_square(&mut []), 0);

        let mut matrix = vec![vec![0, 1], vec![1, 0]];
        assert_eq!(maximal_square(&mut matrix), 1);

        let mut matrix = vec![
            vec![1, 0, 1, 0, 0],
            vec![1, 0, 1, 1, 1],
            vec![1, 1, 1, 1, 1],
            vec![1, 0, 0, 1, 0],
        ];
        assert_eq!(maximal_square(&mut matrix), 4);

        let mut matrix = vec![vec![0]];
        assert_eq!(maximal_square(&mut matrix), 0);
    }
}


/// ## maximum subarray via Dynamic Programming

/// maximum_subarray(array) find the subarray (containing at least one number) which has the largest sum
/// and return its sum.
///
/// A subarray is a contiguous part of an array.
///
/// Arguments:
///     * `array` - an integer array
/// Complexity
///     - time complexity: O(array.length),
///     - space complexity: O(array.length),
pub fn maximum_subarray(array: &[i32]) -> i32 {
    let mut dp = vec![0; array.len()];
    dp[0] = array[0];
    let mut result = dp[0];

    for i in 1..array.len() {
        if dp[i - 1] > 0 {
            dp[i] = dp[i - 1] + array[i];
        } else {
            dp[i] = array[i];
        }
        result = result.max(dp[i]);
    }

    result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn non_negative() {
        //the maximum value: 1 + 0 + 5 + 8 = 14
        let array = vec![1, 0, 5, 8];
        assert_eq!(maximum_subarray(&array), 14);
    }

    #[test]
    fn negative() {
        //the maximum value: -1
        let array = vec![-3, -1, -8, -2];
        assert_eq!(maximum_subarray(&array), -1);
    }

    #[test]
    fn normal() {
        //the maximum value: 3 + (-2) + 5 = 6
        let array = vec![-4, 3, -2, 5, -8];
        assert_eq!(maximum_subarray(&array), 6);
    }

    #[test]
    fn single_element() {
        let array = vec![6];
        assert_eq!(maximum_subarray(&array), 6);
        let array = vec![-6];
        assert_eq!(maximum_subarray(&array), -6);
    }
}


mod coin_change;
mod egg_dropping;
mod fibonacci;
mod fractional_knapsack;
mod is_subsequence;
mod knapsack;
mod longest_common_subsequence;
mod longest_common_substring;
mod longest_continuous_increasing_subsequence;
mod longest_increasing_subsequence;
mod matrix_chain_multiply;
mod maximal_square;
mod maximum_subarray;
mod rod_cutting;
mod snail;
mod subset_generation;

pub use self::coin_change::coin_change;
pub use self::egg_dropping::egg_drop;
pub use self::fibonacci::classical_fibonacci;
pub use self::fibonacci::fibonacci;
pub use self::fibonacci::logarithmic_fibonacci;
pub use self::fibonacci::matrix_fibonacci;
pub use self::fibonacci::memoized_fibonacci;
pub use self::fibonacci::recursive_fibonacci;
pub use self::fractional_knapsack::fractional_knapsack;
pub use self::is_subsequence::is_subsequence;
pub use self::knapsack::knapsack;
pub use self::longest_common_subsequence::longest_common_subsequence;
pub use self::longest_common_substring::longest_common_substring;
pub use self::longest_continuous_increasing_subsequence::longest_continuous_increasing_subsequence;
pub use self::longest_increasing_subsequence::longest_increasing_subsequence;
pub use self::matrix_chain_multiply::matrix_chain_multiply;
pub use self::maximal_square::maximal_square;
pub use self::maximum_subarray::maximum_subarray;
pub use self::rod_cutting::rod_cut;
pub use self::snail::snail;
pub use self::subset_generation::list_subset;


//! Solves the rod-cutting problem
use std::cmp::max;

/// `rod_cut(p)` returns the maximum possible profit if a rod of length `n` = `p.len()`
/// is cut into up to `n` pieces, where the profit gained from each piece of length
/// `l` is determined by `p[l - 1]` and the total profit is the sum of the profit
/// gained from each piece.
///
/// # Arguments
///    - `p` - profit for rods of length 1 to n inclusive
///
/// # Complexity
///    - time complexity: O(n^2),
///    - space complexity: O(n^2),
///
/// where n is the length of `p`.
pub fn rod_cut(p: &[usize]) -> usize {
    let n = p.len();
    // f is the dynamic programming table
    let mut f = vec![0; n];

    for i in 0..n {
        let mut max_price = p[i];
        for j in 1..=i {
            max_price = max(max_price, p[j - 1] + f[i - j]);
        }
        f[i] = max_price;
    }

    // accomodate for input with length zero
    if n != 0 {
        f[n - 1]
    } else {
        0
    }
}

#[cfg(test)]
mod tests {
    use super::rod_cut;

    #[test]
    fn test_rod_cut() {
        assert_eq!(0, rod_cut(&[]));
        assert_eq!(15, rod_cut(&[5, 8, 2]));
        assert_eq!(10, rod_cut(&[1, 5, 8, 9]));
        assert_eq!(25, rod_cut(&[5, 8, 2, 1, 7]));
        assert_eq!(87, rod_cut(&[0, 0, 0, 0, 0, 87]));
        assert_eq!(49, rod_cut(&[7, 6, 5, 4, 3, 2, 1]));
        assert_eq!(22, rod_cut(&[1, 5, 8, 9, 10, 17, 17, 20]));
        assert_eq!(60, rod_cut(&[6, 4, 8, 2, 5, 8, 2, 3, 7, 11]));
        assert_eq!(30, rod_cut(&[1, 5, 8, 9, 10, 17, 17, 20, 24, 30]));
        assert_eq!(12, rod_cut(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]));
    }
}


/// ## Spiral Sorting
///
/// Given an n x m array, return the array elements arranged from outermost elements
/// to the middle element, traveling INWARD FROM TOP-LEFT, CLOCKWISE.
pub fn snail<T: Copy>(matrix: &[Vec<T>]) -> Vec<T> {
    // break on empty matrix
    if matrix.is_empty() || matrix[0].is_empty() {
        return vec![];
    }

    let col_count = matrix[0].len();
    let row_count = matrix.len();

    // Initial maximum/minimum indices
    let mut max_col = col_count - 1;
    let mut min_col = 0;
    let mut max_row = row_count - 1;
    let mut min_row = 0;

    // Initial direction is Right because
    // we start from the top-left corner of the matrix at indices [0][0]
    let mut dir = Direction::Right;
    let mut row = 0;
    let mut col = 0;
    let mut result = Vec::new();

    while result.len() < row_count * col_count {
        result.push(matrix[row][col]);
        dir.snail_move(
            &mut col,
            &mut row,
            &mut min_col,
            &mut max_col,
            &mut min_row,
            &mut max_row,
        );
    }

    result
}

enum Direction {
    Right,
    Left,
    Down,
    Up,
}

impl Direction {
    pub fn snail_move(
        &mut self,
        col: &mut usize,
        row: &mut usize,
        min_col: &mut usize,
        max_col: &mut usize,
        min_row: &mut usize,
        max_row: &mut usize,
    ) {
        match self {
            Self::Right => {
                *col = if *col < *max_col {
                    *col + 1
                } else {
                    *self = Self::Down;
                    *min_row += 1;
                    *row = *min_row;
                    *col
                };
            }

            Self::Down => {
                *row = if *row < *max_row {
                    *row + 1
                } else {
                    *self = Self::Left;
                    *max_col -= 1;
                    *col = *max_col;
                    *row
                };
            }

            Self::Left => {
                *col = if *col > usize::MIN && *col > *min_col {
                    *col - 1
                } else {
                    *self = Self::Up;
                    *max_row -= 1;
                    *row = *max_row;
                    *col
                };
            }

            Self::Up => {
                *row = if *row > usize::MIN && *row > *min_row {
                    *row - 1
                } else {
                    *self = Self::Right;
                    *min_col += 1;
                    *col = *min_col;
                    *row
                };
            }
        };
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_empty() {
        let empty: &[Vec<i32>] = &[vec![]];
        assert_eq!(snail(empty), vec![]);
    }

    #[test]
    fn test_int() {
        let square = &[vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
        assert_eq!(snail(square), vec![1, 2, 3, 6, 9, 8, 7, 4, 5]);
    }

    #[test]
    fn test_char() {
        let square = &[
            vec!['S', 'O', 'M'],
            vec!['E', 'T', 'H'],
            vec!['I', 'N', 'G'],
        ];
        assert_eq!(
            snail(square),
            vec!['S', 'O', 'M', 'H', 'G', 'N', 'I', 'E', 'T']
        );
    }

    #[test]
    fn test_rect() {
        let square = &[
            vec!['H', 'E', 'L', 'L'],
            vec!['O', ' ', 'W', 'O'],
            vec!['R', 'L', 'D', ' '],
        ];
        assert_eq!(
            snail(square),
            vec!['H', 'E', 'L', 'L', 'O', ' ', 'D', 'L', 'R', 'O', ' ', 'W']
        );
    }
}


// list all subset combinations of n element in given set of r element.
// This is a recursive function that collects all subsets of the set of size n
// with the given set of size r.
pub fn list_subset(
    set: &[i32],
    n: usize,
    r: usize,
    index: usize,
    data: &mut [i32],
    i: usize,
) -> Vec<Vec<i32>> {
    let mut res = Vec::new();

    // Current subset is ready to be added to the list
    if i == r {
        let mut subset = Vec::new();
        for j in data.iter().take(r) {
            subset.push(*j);
        }
        res.push(subset);
        return res;
    }

    // When no more elements are there to put in data[]
    if index >= n {
        return res;
    }

    // current is included, put next at next location
    data[i] = set[index];
    res.append(&mut list_subset(set, n, r, index + 1, data, i + 1));

    // current is excluded, replace it with next (Note that
    // i+1 is passed, but index is not changed)
    res.append(&mut list_subset(set, n, r, index + 1, data, i));

    res
}

// Test module
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_print_subset3() {
        let set = [1, 2, 3, 4, 5];
        let n = set.len();
        const R: usize = 3;
        let mut data = [0; R];

        let res = list_subset(&set, n, R, 0, &mut data, 0);

        assert_eq!(
            res,
            vec![
                vec![1, 2, 3],
                vec![1, 2, 4],
                vec![1, 2, 5],
                vec![1, 3, 4],
                vec![1, 3, 5],
                vec![1, 4, 5],
                vec![2, 3, 4],
                vec![2, 3, 5],
                vec![2, 4, 5],
                vec![3, 4, 5]
            ]
        );
    }

    #[test]
    fn test_print_subset4() {
        let set = [1, 2, 3, 4, 5];
        let n = set.len();
        const R: usize = 4;
        let mut data = [0; R];

        let res = list_subset(&set, n, R, 0, &mut data, 0);

        assert_eq!(
            res,
            vec![
                vec![1, 2, 3, 4],
                vec![1, 2, 3, 5],
                vec![1, 2, 4, 5],
                vec![1, 3, 4, 5],
                vec![2, 3, 4, 5]
            ]
        );
    }

    #[test]
    fn test_print_subset5() {
        let set = [1, 2, 3, 4, 5];
        let n = set.len();
        const R: usize = 5;
        let mut data = [0; R];

        let res = list_subset(&set, n, R, 0, &mut data, 0);

        assert_eq!(res, vec![vec![1, 2, 3, 4, 5]]);
    }

    #[test]
    fn test_print_incorrect_subset() {
        let set = [1, 2, 3, 4, 5];
        let n = set.len();
        const R: usize = 6;
        let mut data = [0; R];

        let res = list_subset(&set, n, R, 0, &mut data, 0);

        let result_set: Vec<Vec<i32>> = Vec::new();
        assert_eq!(res, result_set);
    }
}


use std::cmp::Ordering::Equal;

fn sort_by_min_angle(pts: &[(f64, f64)], min: &(f64, f64)) -> Vec<(f64, f64)> {
    let mut points: Vec<(f64, f64, (f64, f64))> = pts
        .iter()
        .map(|x| {
            (
                (x.1 - min.1).atan2(x.0 - min.0),
                // angle
                (x.1 - min.1).hypot(x.0 - min.0),
                // distance (we want the closest to be first)
                *x,
            )
        })
        .collect();
    points.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));
    points.into_iter().map(|x| x.2).collect()
}

// calculates the z coordinate of the vector product of vectors ab and ac
fn calc_z_coord_vector_product(a: &(f64, f64), b: &(f64, f64), c: &(f64, f64)) -> f64 {
    (b.0 - a.0) * (c.1 - a.1) - (c.0 - a.0) * (b.1 - a.1)
}

/*
    If three points are aligned and are part of the convex hull then the three are kept.
    If one doesn't want to keep those points, it is easy to iterate the answer and remove them.

    The first point is the one with the lowest y-coordinate and the lowest x-coordinate.
    Points are then given counter-clockwise, and the closest one is given first if needed.
*/
pub fn convex_hull_graham(pts: &[(f64, f64)]) -> Vec<(f64, f64)> {
    if pts.is_empty() {
        return vec![];
    }

    let mut stack: Vec<(f64, f64)> = vec![];
    let min = pts
        .iter()
        .min_by(|a, b| {
            let ord = a.1.partial_cmp(&b.1).unwrap_or(Equal);
            match ord {
                Equal => a.0.partial_cmp(&b.0).unwrap_or(Equal),
                o => o,
            }
        })
        .unwrap();
    let points = sort_by_min_angle(pts, min);

    if points.len() <= 3 {
        return points;
    }

    for point in points {
        while stack.len() > 1
            && calc_z_coord_vector_product(&stack[stack.len() - 2], &stack[stack.len() - 1], &point)
                < 0.
        {
            stack.pop();
        }
        stack.push(point);
    }

    stack
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty() {
        assert_eq!(convex_hull_graham(&[]), vec![]);
    }

    #[test]
    fn not_enough_points() {
        let list = vec![(0f64, 0f64)];
        assert_eq!(convex_hull_graham(&list), list);
    }

    #[test]
    fn not_enough_points1() {
        let list = vec![(2f64, 2f64), (1f64, 1f64), (0f64, 0f64)];
        let ans = vec![(0f64, 0f64), (1f64, 1f64), (2f64, 2f64)];
        assert_eq!(convex_hull_graham(&list), ans);
    }

    #[test]
    fn not_enough_points2() {
        let list = vec![(2f64, 2f64), (1f64, 2f64), (0f64, 0f64)];
        let ans = vec![(0f64, 0f64), (2f64, 2f64), (1f64, 2f64)];
        assert_eq!(convex_hull_graham(&list), ans);
    }

    #[test]
    // from https://codegolf.stackexchange.com/questions/11035/find-the-convex-hull-of-a-set-of-2d-points
    fn lots_of_points() {
        let list = vec![
            (4.4, 14.),
            (6.7, 15.25),
            (6.9, 12.8),
            (2.1, 11.1),
            (9.5, 14.9),
            (13.2, 11.9),
            (10.3, 12.3),
            (6.8, 9.5),
            (3.3, 7.7),
            (0.6, 5.1),
            (5.3, 2.4),
            (8.45, 4.7),
            (11.5, 9.6),
            (13.8, 7.3),
            (12.9, 3.1),
            (11., 1.1),
        ];
        let ans = vec![
            (11., 1.1),
            (12.9, 3.1),
            (13.8, 7.3),
            (13.2, 11.9),
            (9.5, 14.9),
            (6.7, 15.25),
            (4.4, 14.),
            (2.1, 11.1),
            (0.6, 5.1),
            (5.3, 2.4),
        ];

        assert_eq!(convex_hull_graham(&list), ans);
    }

    #[test]
    // from https://codegolf.stackexchange.com/questions/11035/find-the-convex-hull-of-a-set-of-2d-points
    fn lots_of_points2() {
        let list = vec![
            (1., 0.),
            (1., 1.),
            (1., -1.),
            (0.68957, 0.283647),
            (0.909487, 0.644276),
            (0.0361877, 0.803816),
            (0.583004, 0.91555),
            (-0.748169, 0.210483),
            (-0.553528, -0.967036),
            (0.316709, -0.153861),
            (-0.79267, 0.585945),
            (-0.700164, -0.750994),
            (0.452273, -0.604434),
            (-0.79134, -0.249902),
            (-0.594918, -0.397574),
            (-0.547371, -0.434041),
            (0.958132, -0.499614),
            (0.039941, 0.0990732),
            (-0.891471, -0.464943),
            (0.513187, -0.457062),
            (-0.930053, 0.60341),
            (0.656995, 0.854205),
        ];
        let ans = vec![
            (1., -1.),
            (1., 0.),
            (1., 1.),
            (0.583004, 0.91555),
            (0.0361877, 0.803816),
            (-0.930053, 0.60341),
            (-0.891471, -0.464943),
            (-0.700164, -0.750994),
            (-0.553528, -0.967036),
        ];

        assert_eq!(convex_hull_graham(&list), ans);
    }
}


use std::time::{SystemTime, UNIX_EPOCH};

use crate::math::PCG32;

const DEFAULT: u64 = 4294967296;

fn gen_range(range: usize, generator: &mut PCG32) -> usize {
    generator.get_u64() as usize % range
}

pub fn fisher_yates_shuffle(array: &mut [i32]) {
    let seed = match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(duration) => duration.as_millis() as u64,
        Err(_) => DEFAULT,
    };

    let mut random_generator = PCG32::new_default(seed);

    let len = array.len();

    for i in 0..(len - 2) {
        let r = gen_range(len - i, &mut random_generator);
        array.swap(i, i + r);
    }
}


use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::fmt::Debug;

/// The goal is to showcase how Genetic algorithms generically work
/// See: https://en.wikipedia.org/wiki/Genetic_algorithm for concepts

/// This is the definition of a Chromosome for a genetic algorithm
/// We can picture this as "one contending solution to our problem"
/// It is generic over:
/// * Eval, which could be a float, or any other totally ordered type, so that we can rank solutions to our problem
/// * Rng: a random number generator (could be thread rng, etc.)
pub trait Chromosome<Rng: rand::Rng, Eval> {
    /// Mutates this Chromosome, changing its genes
    fn mutate(&mut self, rng: &mut Rng);

    /// Mixes this chromosome with another one
    fn crossover(&self, other: &Self, rng: &mut Rng) -> Self;

    /// How well this chromosome fits the problem we're trying to solve
    /// **The smaller the better it fits** (we could use abs(... - expected_value) for instance
    fn fitness(&self) -> Eval;
}

pub trait SelectionStrategy<Rng: rand::Rng> {
    fn new(rng: Rng) -> Self;

    /// Selects a portion of the population for reproduction
    /// Could be totally random ones or the ones that fit best, etc.
    /// This assumes the population is sorted by how it fits the solution (the first the better)
    fn select<'a, Eval: Into<f64>, C: Chromosome<Rng, Eval>>(
        &mut self,
        population: &'a [C],
    ) -> (&'a C, &'a C);
}

/// A roulette wheel selection strategy
/// https://en.wikipedia.org/wiki/Fitness_proportionate_selection
pub struct RouletteWheel<Rng: rand::Rng> {
    rng: Rng,
}
impl<Rng: rand::Rng> SelectionStrategy<Rng> for RouletteWheel<Rng> {
    fn new(rng: Rng) -> Self {
        Self { rng }
    }

    fn select<'a, Eval: Into<f64>, C: Chromosome<Rng, Eval>>(
        &mut self,
        population: &'a [C],
    ) -> (&'a C, &'a C) {
        // We will assign a probability for every item in the population, based on its proportion towards the sum of all fitness
        // This would work well for an increasing fitness function, but not in our case of a fitness function for which "lower is better"
        // We thus need to take the reciprocal
        let mut parents = Vec::with_capacity(2);
        let fitnesses: Vec<f64> = population
            .iter()
            .filter_map(|individual| {
                let fitness = individual.fitness().into();
                if individual.fitness().into() == 0.0 {
                    parents.push(individual);
                    None
                } else {
                    Some(1.0 / fitness)
                }
            })
            .collect();
        if parents.len() == 2 {
            return (parents[0], parents[1]);
        }
        let sum: f64 = fitnesses.iter().sum();
        let mut spin = self.rng.gen_range(0.0..=sum);
        for individual in population {
            let fitness: f64 = individual.fitness().into();
            if spin <= fitness {
                parents.push(individual);
                if parents.len() == 2 {
                    return (parents[0], parents[1]);
                }
            } else {
                spin -= fitness;
            }
        }
        panic!("Could not select parents");
    }
}

pub struct Tournament<const K: usize, Rng: rand::Rng> {
    rng: Rng,
}
impl<const K: usize, Rng: rand::Rng> SelectionStrategy<Rng> for Tournament<K, Rng> {
    fn new(rng: Rng) -> Self {
        Self { rng }
    }

    fn select<'a, Eval, C: Chromosome<Rng, Eval>>(
        &mut self,
        population: &'a [C],
    ) -> (&'a C, &'a C) {
        if K < 2 {
            panic!("K must be > 2");
        }
        // This strategy is defined as the following: pick K chromosomes randomly, use the 2 that fits the best
        // We assume the population is sorted
        // This means we can draw K random (distinct) numbers between (0..population.len()) and return the chromosomes at the 2 lowest indices
        let mut picked_indices = BTreeSet::new(); // will keep indices ordered
        while picked_indices.len() < K {
            picked_indices.insert(self.rng.gen_range(0..population.len()));
        }
        let mut iter = picked_indices.into_iter();
        (
            &population[iter.next().unwrap()],
            &population[iter.next().unwrap()],
        )
    }
}

type Comparator<T> = Box<dyn FnMut(&T, &T) -> Ordering>;
pub struct GeneticAlgorithm<
    Rng: rand::Rng,
    Eval: PartialOrd,
    C: Chromosome<Rng, Eval>,
    Selection: SelectionStrategy<Rng>,
> {
    rng: Rng, // will be used to draw random numbers for initial population, mutations and crossovers
    population: Vec<C>, // the set of random solutions (chromosomes)
    threshold: Eval, // Any chromosome fitting over this threshold is considered a valid solution
    max_generations: usize, // So that we don't loop infinitely
    mutation_chance: f64, // what's the probability a chromosome will mutate
    crossover_chance: f64, // what's the probability two chromosomes will cross-over and give birth to a new chromosome
    compare: Comparator<Eval>,
    selection: Selection, // how we will select parent chromosomes for crossing over, see `SelectionStrategy`
}

pub struct GenericAlgorithmParams {
    max_generations: usize,
    mutation_chance: f64,
    crossover_chance: f64,
}

impl<
        Rng: rand::Rng,
        Eval: Into<f64> + PartialOrd + Debug,
        C: Chromosome<Rng, Eval> + Clone + Debug,
        Selection: SelectionStrategy<Rng>,
    > GeneticAlgorithm<Rng, Eval, C, Selection>
{
    pub fn init(
        rng: Rng,
        population: Vec<C>,
        threshold: Eval,
        params: GenericAlgorithmParams,
        compare: Comparator<Eval>,
        selection: Selection,
    ) -> Self {
        let GenericAlgorithmParams {
            max_generations,
            mutation_chance,
            crossover_chance,
        } = params;
        Self {
            rng,
            population,
            threshold,
            max_generations,
            mutation_chance,
            crossover_chance,
            compare,
            selection,
        }
    }

    pub fn solve(&mut self) -> Option<C> {
        let mut generations = 1; // 1st generation is our initial population
        while generations <= self.max_generations {
            // 1. Sort the population by fitness score, remember: the lower the better (so natural ordering)
            self.population
                .sort_by(|c1: &C, c2: &C| (self.compare)(&c1.fitness(), &c2.fitness()));

            // 2. Stop condition: we might have found a good solution
            if let Some(solution) = self.population.first() {
                if solution.fitness() <= self.threshold {
                    return Some(solution).cloned();
                }
            }

            // 3. Apply random mutations to the whole population
            for chromosome in self.population.iter_mut() {
                if self.rng.gen::<f64>() <= self.mutation_chance {
                    chromosome.mutate(&mut self.rng);
                }
            }
            // 4. Select parents that will be mating to create new chromosomes
            let mut new_population = Vec::with_capacity(self.population.len() + 1);
            while new_population.len() < self.population.len() {
                let (p1, p2) = self.selection.select(&self.population);
                if self.rng.gen::<f64>() <= self.crossover_chance {
                    let child = p1.crossover(p2, &mut self.rng);
                    new_population.push(child);
                } else {
                    // keep parents
                    new_population.extend([p1.clone(), p2.clone()]);
                }
            }
            if new_population.len() > self.population.len() {
                // We might have added 2 parents
                new_population.pop();
            }
            self.population = new_population;
            // 5. Rinse & Repeat until we find a proper solution or we reach the maximum number of generations
            generations += 1;
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use crate::general::genetic::{
        Chromosome, GenericAlgorithmParams, GeneticAlgorithm, RouletteWheel, SelectionStrategy,
        Tournament,
    };
    use rand::rngs::ThreadRng;
    use rand::{thread_rng, Rng};
    use std::collections::HashMap;
    use std::fmt::{Debug, Formatter};
    use std::ops::RangeInclusive;

    #[test]
    #[ignore] // Too long and not deterministic enough to be part of CI, more of an example than a test
    fn find_secret() {
        let chars = 'a'..='z';
        let secret = "thisistopsecret".to_owned();
        // Note: we'll pick genes (a, b, c) in the range -10, 10
        #[derive(Clone)]
        struct TestString {
            chars: RangeInclusive<char>,
            secret: String,
            genes: Vec<char>,
        }
        impl TestString {
            fn new(rng: &mut ThreadRng, secret: String, chars: RangeInclusive<char>) -> Self {
                let current = (0..secret.len())
                    .map(|_| rng.gen_range(chars.clone()))
                    .collect::<Vec<_>>();

                Self {
                    chars,
                    secret,
                    genes: current,
                }
            }
        }
        impl Debug for TestString {
            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
                f.write_str(&self.genes.iter().collect::<String>())
            }
        }
        impl Chromosome<ThreadRng, i32> for TestString {
            fn mutate(&mut self, rng: &mut ThreadRng) {
                // let's assume mutations happen completely randomly, one "gene" at a time (i.e. one char at a time)
                let gene_idx = rng.gen_range(0..self.secret.len());
                let new_char = rng.gen_range(self.chars.clone());
                self.genes[gene_idx] = new_char;
            }

            fn crossover(&self, other: &Self, rng: &mut ThreadRng) -> Self {
                // Let's not assume anything here, simply mixing random genes from both parents
                let genes = (0..self.secret.len())
                    .map(|idx| {
                        if rng.gen_bool(0.5) {
                            // pick gene from self
                            self.genes[idx]
                        } else {
                            // pick gene from other parent
                            other.genes[idx]
                        }
                    })
                    .collect();
                Self {
                    chars: self.chars.clone(),
                    secret: self.secret.clone(),
                    genes,
                }
            }

            fn fitness(&self) -> i32 {
                // We are just counting how many chars are distinct from secret
                self.genes
                    .iter()
                    .zip(self.secret.chars())
                    .filter(|(char, expected)| expected != *char)
                    .count() as i32
            }
        }
        let mut rng = thread_rng();
        let pop_count = 1_000;
        let mut population = Vec::with_capacity(pop_count);
        for _ in 0..pop_count {
            population.push(TestString::new(&mut rng, secret.clone(), chars.clone()));
        }
        let selection: Tournament<100, ThreadRng> = Tournament::new(rng.clone());
        let params = GenericAlgorithmParams {
            max_generations: 100,
            mutation_chance: 0.2,
            crossover_chance: 0.4,
        };
        let mut solver =
            GeneticAlgorithm::init(rng, population, 0, params, Box::new(i32::cmp), selection);
        let res = solver.solve();
        assert!(res.is_some());
        assert_eq!(res.unwrap().genes, secret.chars().collect::<Vec<_>>())
    }

    #[test]
    #[ignore] // Too long and not deterministic enough to be part of CI, more of an example than a test
    fn solve_mastermind() {
        #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
        enum ColoredPeg {
            Red,
            Yellow,
            Green,
            Blue,
            White,
            Black,
        }
        struct GuessAnswer {
            right_pos: i32, // right color at the right pos
            wrong_pos: i32, // right color, but at wrong pos
        }
        #[derive(Clone, Debug)]
        struct CodeMaker {
            // the player coming up with a secret code
            code: [ColoredPeg; 4],
            count_by_color: HashMap<ColoredPeg, usize>,
        }
        impl CodeMaker {
            fn new(code: [ColoredPeg; 4]) -> Self {
                let mut count_by_color = HashMap::with_capacity(4);
                for peg in &code {
                    *count_by_color.entry(*peg).or_insert(0) += 1;
                }
                Self {
                    code,
                    count_by_color,
                }
            }
            fn eval(&self, guess: &[ColoredPeg; 4]) -> GuessAnswer {
                let mut right_pos = 0;
                let mut wrong_pos = 0;
                let mut idx_by_colors = self.count_by_color.clone();
                for (idx, color) in guess.iter().enumerate() {
                    if self.code[idx] == *color {
                        right_pos += 1;
                        let count = idx_by_colors.get_mut(color).unwrap();
                        *count -= 1; // don't reuse to say "right color but wrong pos"
                        if *count == 0 {
                            idx_by_colors.remove(color);
                        }
                    }
                }
                for (idx, color) in guess.iter().enumerate() {
                    if self.code[idx] != *color {
                        // try to use another color
                        if let Some(count) = idx_by_colors.get_mut(color) {
                            *count -= 1;
                            if *count == 0 {
                                idx_by_colors.remove(color);
                            }
                            wrong_pos += 1;
                        }
                    }
                }
                GuessAnswer {
                    right_pos,
                    wrong_pos,
                }
            }
        }

        #[derive(Clone)]
        struct CodeBreaker {
            maker: CodeMaker, // so that we can ask the code maker if our guess is good or not
            guess: [ColoredPeg; 4],
        }
        impl Debug for CodeBreaker {
            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
                f.write_str(format!("{:?}", self.guess).as_str())
            }
        }
        fn random_color(rng: &mut ThreadRng) -> ColoredPeg {
            match rng.gen_range(0..=5) {
                0 => ColoredPeg::Red,
                1 => ColoredPeg::Yellow,
                2 => ColoredPeg::Green,
                3 => ColoredPeg::Blue,
                4 => ColoredPeg::White,
                _ => ColoredPeg::Black,
            }
        }
        fn random_guess(rng: &mut ThreadRng) -> [ColoredPeg; 4] {
            std::array::from_fn(|_| random_color(rng))
        }
        impl Chromosome<ThreadRng, i32> for CodeBreaker {
            fn mutate(&mut self, rng: &mut ThreadRng) {
                // change one random color
                let idx = rng.gen_range(0..4);
                self.guess[idx] = random_color(rng);
            }

            fn crossover(&self, other: &Self, rng: &mut ThreadRng) -> Self {
                Self {
                    maker: self.maker.clone(),
                    guess: std::array::from_fn(|i| {
                        if rng.gen::<f64>() < 0.5 {
                            self.guess[i]
                        } else {
                            other.guess[i]
                        }
                    }),
                }
            }

            fn fitness(&self) -> i32 {
                // Ask the code maker for the result
                let answer = self.maker.eval(&self.guess);
                // Remember: we need to have fitness return 0 if the guess is good, and the higher number we return, the further we are from a proper solution
                let mut res = 32; // worst case scenario, everything is wrong
                res -= answer.right_pos * 8; // count 8 points for the right item at the right spot
                res -= answer.wrong_pos; // count 1 point for having a right color
                res
            }
        }
        let code = [
            ColoredPeg::Red,
            ColoredPeg::Red,
            ColoredPeg::White,
            ColoredPeg::Blue,
        ];
        let maker = CodeMaker::new(code);
        let population_count = 10;
        let params = GenericAlgorithmParams {
            max_generations: 100,
            mutation_chance: 0.5,
            crossover_chance: 0.3,
        };
        let mut rng = thread_rng();
        let mut initial_pop = Vec::with_capacity(population_count);
        for _ in 0..population_count {
            initial_pop.push(CodeBreaker {
                maker: maker.clone(),
                guess: random_guess(&mut rng),
            });
        }
        let selection = RouletteWheel { rng: rng.clone() };
        let mut solver =
            GeneticAlgorithm::init(rng, initial_pop, 0, params, Box::new(i32::cmp), selection);
        let res = solver.solve();
        assert!(res.is_some());
        assert_eq!(code, res.unwrap().guess);
    }
}


pub fn hanoi(n: i32, from: i32, to: i32, via: i32, moves: &mut Vec<(i32, i32)>) {
    if n > 0 {
        hanoi(n - 1, from, via, to, moves);
        moves.push((from, to));
        hanoi(n - 1, via, to, from, moves);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn hanoi_simple() {
        let correct_solution: Vec<(i32, i32)> =
            vec![(1, 3), (1, 2), (3, 2), (1, 3), (2, 1), (2, 3), (1, 3)];
        let mut our_solution: Vec<(i32, i32)> = Vec::new();
        hanoi(3, 1, 3, 2, &mut our_solution);
        assert_eq!(correct_solution, our_solution);
    }
}


use std::{
    cmp::Ordering,
    collections::{BTreeMap, BinaryHeap},
};

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct HuffmanValue {
    // For the `value` to overflow, the sum of frequencies should be bigger
    // than u64. So we should be safe here
    /// The encoded value
    pub value: u64,
    /// number of bits used (up to 64)
    pub bits: u32,
}

pub struct HuffmanNode<T> {
    pub left: Option<Box<HuffmanNode<T>>>,
    pub right: Option<Box<HuffmanNode<T>>>,
    pub symbol: Option<T>,
    pub frequency: u64,
}

impl<T> PartialEq for HuffmanNode<T> {
    fn eq(&self, other: &Self) -> bool {
        self.frequency == other.frequency
    }
}

impl<T> PartialOrd for HuffmanNode<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.frequency.cmp(&other.frequency).reverse())
    }
}

impl<T> Eq for HuffmanNode<T> {}

impl<T> Ord for HuffmanNode<T> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.frequency.cmp(&other.frequency).reverse()
    }
}

impl<T: Clone + Copy + Ord> HuffmanNode<T> {
    /// Turn the tree into the map that can be used in encoding
    pub fn get_alphabet(
        height: u32,
        path: u64,
        node: &HuffmanNode<T>,
        map: &mut BTreeMap<T, HuffmanValue>,
    ) {
        match node.symbol {
            Some(s) => {
                map.insert(
                    s,
                    HuffmanValue {
                        value: path,
                        bits: height,
                    },
                );
            }
            None => {
                Self::get_alphabet(height + 1, path, node.left.as_ref().unwrap(), map);
                Self::get_alphabet(
                    height + 1,
                    path | (1 << height),
                    node.right.as_ref().unwrap(),
                    map,
                );
            }
        }
    }
}

pub struct HuffmanDictionary<T> {
    pub alphabet: BTreeMap<T, HuffmanValue>,
    pub root: HuffmanNode<T>,
}

impl<T: Clone + Copy + Ord> HuffmanDictionary<T> {
    /// The list of alphabet symbols and their respective frequency should
    /// be given as input
    pub fn new(alphabet: &[(T, u64)]) -> Self {
        let mut alph: BTreeMap<T, HuffmanValue> = BTreeMap::new();
        let mut queue: BinaryHeap<HuffmanNode<T>> = BinaryHeap::new();
        for (symbol, freq) in alphabet.iter() {
            queue.push(HuffmanNode {
                left: None,
                right: None,
                symbol: Some(*symbol),
                frequency: *freq,
            });
        }
        for _ in 1..alphabet.len() {
            let left = queue.pop().unwrap();
            let right = queue.pop().unwrap();
            let sm_freq = left.frequency + right.frequency;
            queue.push(HuffmanNode {
                left: Some(Box::new(left)),
                right: Some(Box::new(right)),
                symbol: None,
                frequency: sm_freq,
            });
        }
        let root = queue.pop().unwrap();
        HuffmanNode::get_alphabet(0, 0, &root, &mut alph);
        HuffmanDictionary {
            alphabet: alph,
            root,
        }
    }
    pub fn encode(&self, data: &[T]) -> HuffmanEncoding {
        let mut result = HuffmanEncoding::new();
        data.iter()
            .for_each(|value| result.add_data(*self.alphabet.get(value).unwrap()));
        result
    }
}
pub struct HuffmanEncoding {
    pub num_bits: u64,
    pub data: Vec<u64>,
}

impl Default for HuffmanEncoding {
    fn default() -> Self {
        Self::new()
    }
}

impl HuffmanEncoding {
    pub fn new() -> Self {
        HuffmanEncoding {
            num_bits: 0,
            data: vec![0],
        }
    }
    #[inline]
    pub fn add_data(&mut self, data: HuffmanValue) {
        let shift = (self.num_bits & 63) as u32;
        let val = data.value;
        *self.data.last_mut().unwrap() |= val.wrapping_shl(shift);
        if (shift + data.bits) >= 64 {
            self.data.push(val.wrapping_shr(64 - shift));
        }
        self.num_bits += data.bits as u64;
    }
    fn get_bit(&self, pos: u64) -> bool {
        (self.data[(pos >> 6) as usize] & (1 << (pos & 63))) != 0
    }
    /// In case the encoding is invalid, `None` is returned
    pub fn decode<T: Clone + Copy + Ord>(&self, dict: &HuffmanDictionary<T>) -> Option<Vec<T>> {
        let mut state = &dict.root;
        let mut result: Vec<T> = vec![];
        for i in 0..self.num_bits {
            if state.symbol.is_some() {
                result.push(state.symbol.unwrap());
                state = &dict.root;
            }
            match self.get_bit(i) {
                false => state = state.left.as_ref().unwrap(),
                true => state = state.right.as_ref().unwrap(),
            }
        }
        if self.num_bits > 0 {
            result.push(state.symbol?);
        }
        Some(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    fn get_frequency(bytes: &[u8]) -> Vec<(u8, u64)> {
        let mut cnts: Vec<u64> = vec![0; 256];
        bytes.iter().for_each(|&b| cnts[b as usize] += 1);
        let mut result = vec![];
        cnts.iter()
            .enumerate()
            .filter(|(_, &v)| v > 0)
            .for_each(|(b, &cnt)| result.push((b as u8, cnt)));
        result
    }
    #[test]
    fn small_text() {
        let text = "Hello world";
        let bytes = text.as_bytes();
        let freq = get_frequency(bytes);
        let dict = HuffmanDictionary::new(&freq);
        let encoded = dict.encode(bytes);
        assert_eq!(encoded.num_bits, 32);
        let decoded = encoded.decode(&dict).unwrap();
        assert_eq!(decoded, bytes);
    }
    #[test]
    fn lorem_ipsum() {
        let text = concat!(
            "The quick brown fox jumped over the lazy dog.",
            "Lorem ipsum dolor sit amet, consectetur ",
            "adipiscing elit, sed do eiusmod tempor incididunt ut labore et ",
            "dolore magna aliqua. Facilisis magna etiam tempor orci. Nullam ",
            "non nisi est sit amet facilisis magna. Commodo nulla facilisi ",
            "nullam vehicula. Interdum posuere lorem ipsum dolor. Elit eget ",
            "gravida cum sociis natoque penatibus. Dictum sit amet justo donec ",
            "enim. Tempor commodo ullamcorper a lacus vestibulum sed. Nisl ",
            "suscipit adipiscing bibendum est ultricies. Sit amet aliquam id ",
            "diam maecenas ultricies."
        );
        let bytes = text.as_bytes();
        let freq = get_frequency(bytes);
        let dict = HuffmanDictionary::new(&freq);
        let encoded = dict.encode(bytes);
        assert_eq!(encoded.num_bits, 2372);
        let decoded = encoded.decode(&dict).unwrap();
        assert_eq!(decoded, bytes);

        let text = "The dictionary should work on other texts too";
        let bytes = text.as_bytes();
        let encoded = dict.encode(bytes);
        assert_eq!(encoded.num_bits, 215);
        let decoded = encoded.decode(&dict).unwrap();
        assert_eq!(decoded, bytes);
    }
}


// Macro to implement kmeans for both f64 and f32 without writing everything
// twice or importing the `num` crate
macro_rules! impl_kmeans {
    ($kind: ty, $modname: ident) => {
        // Since we can't overload methods in rust, we have to use namespacing
        pub mod $modname {
            use std::$modname::INFINITY;

            /// computes sum of squared deviation between two identically sized vectors
            /// `x`, and `y`.
            fn distance(x: &[$kind], y: &[$kind]) -> $kind {
                x.iter()
                    .zip(y.iter())
                    .fold(0.0, |dist, (&xi, &yi)| dist + (xi - yi).powi(2))
            }

            /// Returns a vector containing the indices zi in {0, ..., K-1} of
            /// the centroid nearest to each datum.
            fn nearest_centroids(xs: &[Vec<$kind>], centroids: &[Vec<$kind>]) -> Vec<usize> {
                xs.iter()
                    .map(|xi| {
                        // Find the argmin by folding using a tuple containing the argmin
                        // and the minimum distance.
                        let (argmin, _) = centroids.iter().enumerate().fold(
                            (0_usize, INFINITY),
                            |(min_ix, min_dist), (ix, ci)| {
                                let dist = distance(xi, ci);
                                if dist < min_dist {
                                    (ix, dist)
                                } else {
                                    (min_ix, min_dist)
                                }
                            },
                        );
                        argmin
                    })
                    .collect()
            }

            /// Recompute the centroids given the current clustering
            fn recompute_centroids(
                xs: &[Vec<$kind>],
                clustering: &[usize],
                k: usize,
            ) -> Vec<Vec<$kind>> {
                let ndims = xs[0].len();

                // NOTE: Kind of inefficient because we sweep all the data from each of the
                // k centroids.
                (0..k)
                    .map(|cluster_ix| {
                        let mut centroid: Vec<$kind> = vec![0.0; ndims];
                        let mut n_cluster: $kind = 0.0;
                        xs.iter().zip(clustering.iter()).for_each(|(xi, &zi)| {
                            if zi == cluster_ix {
                                n_cluster += 1.0;
                                xi.iter().enumerate().for_each(|(j, &x_ij)| {
                                    centroid[j] += x_ij;
                                });
                            }
                        });
                        centroid.iter().map(|&c_j| c_j / n_cluster).collect()
                    })
                    .collect()
            }

            /// Assign the N D-dimensional data, `xs`, to `k` clusters using K-Means clustering
            pub fn kmeans(xs: Vec<Vec<$kind>>, k: usize) -> Vec<usize> {
                assert!(xs.len() >= k);

                // Rather than pulling in a dependency to radomly select the staring
                // points for the centroids, we're going to deterministally choose them by
                // slecting evenly spaced points in `xs`
                let n_per_cluster: usize = xs.len() / k;
                let centroids: Vec<Vec<$kind>> =
                    (0..k).map(|j| xs[j * n_per_cluster].clone()).collect();

                let mut clustering = nearest_centroids(&xs, &centroids);

                loop {
                    let centroids = recompute_centroids(&xs, &clustering, k);
                    let new_clustering = nearest_centroids(&xs, &centroids);

                    // loop until the clustering doesn't change after the new centroids are computed
                    if new_clustering
                        .iter()
                        .zip(clustering.iter())
                        .all(|(&za, &zb)| za == zb)
                    {
                        // We need to use `return` to break out of the `loop`
                        return clustering;
                    } else {
                        clustering = new_clustering;
                    }
                }
            }
        }
    };
}

// generate code for kmeans for f32 and f64 data
impl_kmeans!(f64, f64);
impl_kmeans!(f32, f32);

#[cfg(test)]
mod test {
    use self::super::f64::kmeans;

    #[test]
    fn easy_univariate_clustering() {
        let xs: Vec<Vec<f64>> = vec![
            vec![-1.1],
            vec![-1.2],
            vec![-1.3],
            vec![-1.4],
            vec![1.1],
            vec![1.2],
            vec![1.3],
            vec![1.4],
        ];
        let clustering = kmeans(xs, 2);
        assert_eq!(clustering, vec![0, 0, 0, 0, 1, 1, 1, 1]);
    }

    #[test]
    fn easy_univariate_clustering_odd_number_of_data() {
        let xs: Vec<Vec<f64>> = vec![
            vec![-1.1],
            vec![-1.2],
            vec![-1.3],
            vec![-1.4],
            vec![1.1],
            vec![1.2],
            vec![1.3],
            vec![1.4],
            vec![1.5],
        ];
        let clustering = kmeans(xs, 2);
        assert_eq!(clustering, vec![0, 0, 0, 0, 1, 1, 1, 1, 1]);
    }

    #[test]
    fn easy_bivariate_clustering() {
        let xs: Vec<Vec<f64>> = vec![
            vec![-1.1, 0.2],
            vec![-1.2, 0.3],
            vec![-1.3, 0.1],
            vec![-1.4, 0.4],
            vec![1.1, -1.1],
            vec![1.2, -1.0],
            vec![1.3, -1.2],
            vec![1.4, -1.3],
        ];
        let clustering = kmeans(xs, 2);
        assert_eq!(clustering, vec![0, 0, 0, 0, 1, 1, 1, 1]);
    }

    #[test]
    fn high_dims() {
        let xs: Vec<Vec<f64>> = vec![
            vec![-2.7825343, -1.7604825, -5.5550113, -2.9752946, -2.7874138],
            vec![-2.9847919, -3.8209332, -2.1531757, -2.2710119, -2.3582877],
            vec![-3.0109320, -2.2366132, -2.8048492, -1.2632331, -4.5755581],
            vec![-2.8432186, -1.0383805, -2.2022826, -2.7435962, -2.0013399],
            vec![-2.6638082, -3.5520086, -1.3684702, -2.1562444, -1.3186447],
            vec![1.7409171, 1.9687576, 4.7162628, 4.5743537, 3.7905611],
            vec![3.2932369, 2.8508700, 2.5580937, 2.0437325, 4.2192562],
            vec![2.5843321, 2.8329818, 2.1329531, 3.2562319, 2.4878733],
            vec![2.1859638, 3.2880048, 3.7018615, 2.3641232, 1.6281994],
            vec![2.6201773, 0.9006588, 2.6774097, 1.8188620, 1.6076493],
        ];

        let clustering = kmeans(xs, 2);
        assert_eq!(clustering, vec![0, 0, 0, 0, 0, 1, 1, 1, 1, 1]);
    }
}


use std::collections::BTreeSet;

// Find minimum excluded number from a set of given numbers using a set
/// Finds the MEX of the values provided in `arr`
/// Uses [`BTreeSet`](std::collections::BTreeSet)
/// O(nlog(n)) implementation
pub fn mex_using_set(arr: &[i64]) -> i64 {
    let mut s: BTreeSet<i64> = BTreeSet::new();
    for i in 0..arr.len() + 1 {
        s.insert(i as i64);
    }
    for x in arr {
        s.remove(x);
    }
    // TODO: change the next 10 lines to *s.first().unwrap() when merged into stable
    // set should never have 0 elements
    if let Some(x) = s.into_iter().next() {
        x
    } else {
        panic!("Some unknown error in mex_using_set")
    }
}
/// Finds the MEX of the values provided in `arr`
/// Uses sorting
/// O(nlog(n)) implementation
pub fn mex_using_sort(arr: &[i64]) -> i64 {
    let mut arr = arr.to_vec();
    arr.sort();
    let mut mex = 0;
    for x in arr {
        if x == mex {
            mex += 1;
        }
    }
    mex
}

#[cfg(test)]
mod tests {
    use super::*;
    struct MexTests {
        test_arrays: Vec<Vec<i64>>,
        outputs: Vec<i64>,
    }
    impl MexTests {
        fn new() -> Self {
            Self {
                test_arrays: vec![
                    vec![-1, 0, 1, 2, 3],
                    vec![-100, 0, 1, 2, 3, 5],
                    vec![-1000000, 0, 1, 2, 5],
                    vec![2, 0, 1, 2, 4],
                    vec![1, 2, 3, 0, 4],
                    vec![0, 1, 5, 2, 4, 3],
                    vec![0, 1, 2, 3, 4, 5, 6],
                    vec![0, 1, 2, 3, 4, 5, 6, 7],
                    vec![0, 1, 2, 3, 4, 5, 6, 7, 8],
                ],
                outputs: vec![4, 4, 3, 3, 5, 6, 7, 8, 9],
            }
        }
        fn test_function(&self, f: fn(&[i64]) -> i64) {
            for (nums, output) in self.test_arrays.iter().zip(self.outputs.iter()) {
                assert_eq!(f(nums), *output);
            }
        }
    }
    #[test]
    fn test_mex_using_set() {
        let tests = MexTests::new();
        mex_using_set(&[1, 23, 3]);
        tests.test_function(mex_using_set);
    }
    #[test]
    fn test_mex_using_sort() {
        let tests = MexTests::new();
        tests.test_function(mex_using_sort);
    }
}


mod convex_hull;
mod fisher_yates_shuffle;
mod genetic;
mod hanoi;
mod huffman_encoding;
mod kmeans;
mod mex;
mod nqueens;
mod permutations;
mod two_sum;

pub use self::convex_hull::convex_hull_graham;
pub use self::fisher_yates_shuffle::fisher_yates_shuffle;
pub use self::genetic::GeneticAlgorithm;
pub use self::hanoi::hanoi;
pub use self::huffman_encoding::{HuffmanDictionary, HuffmanEncoding};
pub use self::kmeans::f32::kmeans as kmeans_f32;
pub use self::kmeans::f64::kmeans as kmeans_f64;
pub use self::mex::mex_using_set;
pub use self::mex::mex_using_sort;
pub use self::nqueens::nqueens;
pub use self::permutations::{
    heap_permute, permute, permute_unique, steinhaus_johnson_trotter_permute,
};
pub use self::two_sum::two_sum;


/*
The n-Queens search is a backtracking algorithm. Each row of the Chess board where a Queen is
placed is dependent on all earlier rows. As only one Queen can fit per row, a one-dimensional
integer array is used to represent the Queen's offset on each row.
*/
pub fn nqueens(board_width: i64) -> Result<Vec<i64>, &'static str> {
    let mut board_rows = vec![0; board_width as usize];
    let mut conflict;
    let mut current_row = 0;

    //Process by row up to the current active row
    loop {
        conflict = false;

        //Column review of previous rows
        for review_index in 0..current_row {
            //Calculate the diagonals of earlier rows where a Queen would be a conflict
            let left = board_rows[review_index] - (current_row as i64 - review_index as i64);
            let right = board_rows[review_index] + (current_row as i64 - review_index as i64);

            if board_rows[current_row] == board_rows[review_index]
                || (left >= 0 && left == board_rows[current_row])
                || (right < board_width && right == board_rows[current_row])
            {
                conflict = true;
                break;
            }
        }

        match conflict {
            true => {
                board_rows[current_row] += 1;

                if current_row == 0 && board_rows[current_row] == board_width {
                    return Err("No solution exists for specificed board size.");
                }

                while board_rows[current_row] == board_width {
                    board_rows[current_row] = 0;

                    if current_row == 0 {
                        return Err("No solution exists for specificed board size.");
                    }

                    current_row -= 1;
                    board_rows[current_row] += 1;
                }
            }
            _ => {
                current_row += 1;

                if current_row as i64 == board_width {
                    break;
                }
            }
        }
    }

    Ok(board_rows)
}

#[cfg(test)]
mod test {
    use super::*;

    fn check_board(board: &Vec<i64>) -> bool {
        for current_row in 0..board.len() {
            //Column review
            for review_index in 0..current_row {
                //Look for any conflict.
                let left = board[review_index] - (current_row as i64 - review_index as i64);
                let right = board[review_index] + (current_row as i64 - review_index as i64);

                if board[current_row] == board[review_index]
                    || (left >= 0 && left == board[current_row])
                    || (right < board.len() as i64 && right == board[current_row])
                {
                    return false;
                }
            }
        }
        true
    }

    #[test]
    fn test_board_size_4() {
        let board = nqueens(4).expect("Error propagated.");
        assert_eq!(board, vec![1, 3, 0, 2]);
        assert!(check_board(&board));
    }

    #[test]
    fn test_board_size_7() {
        let board = nqueens(7).expect("Error propagated.");
        assert_eq!(board, vec![0, 2, 4, 6, 1, 3, 5]);
        assert!(check_board(&board));
    }
}


use std::collections::HashMap;

/// Given an array of integers nums and an integer target,
/// return indices of the two numbers such that they add up to target.
///
/// # Parameters
///
/// - `nums`: A list of numbers to check.
/// - `target`: The target sum.
///
/// # Returns
///
/// If the target sum is found in the array, the indices of the augend and
/// addend are returned as a tuple.
///
/// If the target sum cannot be found in the array, `None` is returned.
///
pub fn two_sum(nums: Vec<i32>, target: i32) -> Option<(usize, usize)> {
    // This HashMap is used to look up a corresponding index in the `nums` list.
    // Given that we know where we are at in the array, we can look up our
    // complementary value using this table and only go through the list once.
    //
    // We populate this table with distances from the target. As we go through
    // the list, a distance is computed like so:
    //
    //     `target - current_value`
    //
    // This distance also tells us about the complementary value we're looking
    // for in the array. If we don't find that value, we insert `current_value`
    // into the table for future look-ups. As we iterate through the list,
    // the number we just inserted might be the perfect distance for another
    // number, and we've found a match!
    //
    let mut distance_table: HashMap<i32, usize> = HashMap::new();

    for (i, current_value) in nums.iter().enumerate() {
        match distance_table.get(&(target - current_value)) {
            Some(j) => return Some((i, *j)),
            _ => distance_table.insert(*current_value, i),
        };
    }

    // No match was found!
    None
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test() {
        let nums = vec![2, 7, 11, 15];
        assert_eq!(two_sum(nums, 9), Some((1, 0)));

        let nums = vec![3, 2, 4];
        assert_eq!(two_sum(nums, 6), Some((2, 1)));

        let nums = vec![3, 3];
        assert_eq!(two_sum(nums, 6), Some((1, 0)));

        let nums = vec![2, 7, 11, 15];
        assert_eq!(two_sum(nums, 16), None);
    }
}


use std::fmt::Debug;

/// Computes all permutations of an array using Heap's algorithm
/// Read `recurse_naive` first, since we're building on top of the same intuition
pub fn heap_permute<T: Clone + Debug>(arr: &[T]) -> Vec<Vec<T>> {
    if arr.is_empty() {
        return vec![vec![]];
    }
    let n = arr.len();
    let mut collector = Vec::with_capacity((1..=n).product()); // collects the permuted arrays
    let mut arr = arr.to_owned(); // Heap's algorithm needs to mutate the array
    heap_recurse(&mut arr, n, &mut collector);
    collector
}

fn heap_recurse<T: Clone + Debug>(arr: &mut [T], k: usize, collector: &mut Vec<Vec<T>>) {
    if k == 1 {
        // same base-case as in the naive version
        collector.push((*arr).to_owned());
        return;
    }
    // Remember the naive recursion. We did the following: swap(i, last), recurse, swap back(i, last)
    // Heap's algorithm has a more clever way of permuting the elements so that we never need to swap back!
    for i in 0..k {
        // now deal with [a, b]
        let swap_idx = if k % 2 == 0 { i } else { 0 };
        arr.swap(swap_idx, k - 1);
        heap_recurse(arr, k - 1, collector);
    }
}

#[cfg(test)]
mod tests {
    use quickcheck_macros::quickcheck;

    use crate::general::permutations::heap_permute;
    use crate::general::permutations::tests::{
        assert_permutations, assert_valid_permutation, NotTooBigVec,
    };

    #[test]
    fn test_3_different_values() {
        let original = vec![1, 2, 3];
        let res = heap_permute(&original);
        assert_eq!(res.len(), 6); // 3!
        for permut in res {
            assert_valid_permutation(&original, &permut)
        }
    }

    #[test]
    fn test_3_times_the_same_value() {
        let original = vec![1, 1, 1];
        let res = heap_permute(&original);
        assert_eq!(res.len(), 6); // 3!
        for permut in res {
            assert_valid_permutation(&original, &permut)
        }
    }

    #[quickcheck]
    fn test_some_elements(NotTooBigVec { inner: original }: NotTooBigVec) {
        let permutations = heap_permute(&original);
        assert_permutations(&original, &permutations)
    }
}


mod heap;
mod naive;
mod steinhaus_johnson_trotter;

pub use self::heap::heap_permute;
pub use self::naive::{permute, permute_unique};
pub use self::steinhaus_johnson_trotter::steinhaus_johnson_trotter_permute;

#[cfg(test)]
mod tests {
    use quickcheck::{Arbitrary, Gen};
    use std::collections::HashMap;

    pub(crate) fn assert_permutations(original: &[i32], permutations: &[Vec<i32>]) {
        if original.is_empty() {
            assert_eq!(vec![vec![] as Vec<i32>], permutations);
            return;
        }
        let n = original.len();
        assert_eq!((1..=n).product::<usize>(), permutations.len()); // n!
        for permut in permutations {
            assert_valid_permutation(original, permut);
        }
    }

    pub(crate) fn assert_valid_permutation(original: &[i32], permuted: &[i32]) {
        assert_eq!(original.len(), permuted.len());
        let mut indices = HashMap::with_capacity(original.len());
        for value in original {
            *indices.entry(*value).or_insert(0) += 1;
        }
        for permut_value in permuted {
            let count = indices.get_mut(permut_value).unwrap_or_else(|| {
                panic!(
                    "Value {} appears too many times in permutation",
                    permut_value,
                )
            });
            *count -= 1; // use this value
            if *count == 0 {
                indices.remove(permut_value); // so that we can simply check every value has been removed properly
            }
        }
        assert!(indices.is_empty())
    }

    #[test]
    fn test_valid_permutations() {
        assert_valid_permutation(&[1, 2, 3], &[1, 2, 3]);
        assert_valid_permutation(&[1, 2, 3], &[1, 3, 2]);
        assert_valid_permutation(&[1, 2, 3], &[2, 1, 3]);
        assert_valid_permutation(&[1, 2, 3], &[2, 3, 1]);
        assert_valid_permutation(&[1, 2, 3], &[3, 1, 2]);
        assert_valid_permutation(&[1, 2, 3], &[3, 2, 1]);
    }

    #[test]
    #[should_panic]
    fn test_invalid_permutation_1() {
        assert_valid_permutation(&[1, 2, 3], &[4, 2, 3]);
    }

    #[test]
    #[should_panic]
    fn test_invalid_permutation_2() {
        assert_valid_permutation(&[1, 2, 3], &[1, 4, 3]);
    }

    #[test]
    #[should_panic]
    fn test_invalid_permutation_3() {
        assert_valid_permutation(&[1, 2, 3], &[1, 2, 4]);
    }

    #[test]
    #[should_panic]
    fn test_invalid_permutation_repeat() {
        assert_valid_permutation(&[1, 2, 3], &[1, 2, 2]);
    }

    /// A Data Structure for testing permutations
    /// Holds a Vec<i32> with just a few items, so that it's not too long to compute permutations
    #[derive(Debug, Clone)]
    pub(crate) struct NotTooBigVec {
        pub(crate) inner: Vec<i32>, // opaque type alias so that we can implement Arbitrary
    }

    const MAX_SIZE: usize = 8; // 8! ~= 40k permutations already
    impl Arbitrary for NotTooBigVec {
        fn arbitrary(g: &mut Gen) -> Self {
            let size = usize::arbitrary(g) % MAX_SIZE;
            let res = (0..size).map(|_| i32::arbitrary(g)).collect();
            NotTooBigVec { inner: res }
        }
    }
}


use std::collections::HashSet;
use std::fmt::Debug;
use std::hash::Hash;

/// Here's a basic (naive) implementation for generating permutations
pub fn permute<T: Clone + Debug>(arr: &[T]) -> Vec<Vec<T>> {
    if arr.is_empty() {
        return vec![vec![]];
    }
    let n = arr.len();
    let count = (1..=n).product(); // n! permutations
    let mut collector = Vec::with_capacity(count); // collects the permuted arrays
    let mut arr = arr.to_owned(); // we'll need to mutate the array

    // the idea is the following: imagine [a, b, c]
    // always swap an item with the last item, then generate all permutations from the first k characters
    // permute_recurse(arr, k - 1, collector); // leave the last character alone, and permute the first k-1 characters
    permute_recurse(&mut arr, n, &mut collector);
    collector
}

fn permute_recurse<T: Clone + Debug>(arr: &mut Vec<T>, k: usize, collector: &mut Vec<Vec<T>>) {
    if k == 1 {
        collector.push(arr.to_owned());
        return;
    }
    for i in 0..k {
        arr.swap(i, k - 1); // swap i with the last character
        permute_recurse(arr, k - 1, collector); // collect the permutations of the rest
        arr.swap(i, k - 1); // swap back to original
    }
}

/// A common variation of generating permutations is to generate only unique permutations
/// Of course, we could use the version above together with a Set as collector instead of a Vec.
/// But let's try something different: how can we avoid to generate duplicated permutations in the first place, can we tweak the algorithm above?
pub fn permute_unique<T: Clone + Debug + Eq + Hash + Copy>(arr: &[T]) -> Vec<Vec<T>> {
    if arr.is_empty() {
        return vec![vec![]];
    }
    let n = arr.len();
    let count = (1..=n).product(); // n! permutations
    let mut collector = Vec::with_capacity(count); // collects the permuted arrays
    let mut arr = arr.to_owned(); // Heap's algorithm needs to mutate the array
    permute_recurse_unique(&mut arr, n, &mut collector);
    collector
}

fn permute_recurse_unique<T: Clone + Debug + Eq + Hash + Copy>(
    arr: &mut Vec<T>,
    k: usize,
    collector: &mut Vec<Vec<T>>,
) {
    // We have the same base-case as previously, whenever we reach the first element in the array, collect the result
    if k == 1 {
        collector.push(arr.to_owned());
        return;
    }
    // We'll keep the same idea (swap with last item, and generate all permutations for the first k - 1)
    // But we'll have to be careful though: how would we generate duplicates?
    // Basically if, when swapping i with k-1, we generate the exact same array as in a previous iteration
    // Imagine [a, a, b]
    // i = 0:
    //  Swap (a, b) => [b, a, a], fix 'a' as last, and generate all permutations of [b, a] => [b, a, a], [a, b, a]
    //  Swap Back to [a, a, b]
    // i = 1:
    //  Swap(a, b) => [b, a, a], we've done that already!!
    let mut swapped = HashSet::with_capacity(k);
    for i in 0..k {
        if swapped.contains(&arr[i]) {
            continue;
        }
        swapped.insert(arr[i]);
        arr.swap(i, k - 1); // swap i with the last character
        permute_recurse_unique(arr, k - 1, collector); // collect the permutations
        arr.swap(i, k - 1); // go back to original
    }
}

#[cfg(test)]
mod tests {
    use crate::general::permutations::naive::{permute, permute_unique};
    use crate::general::permutations::tests::{
        assert_permutations, assert_valid_permutation, NotTooBigVec,
    };
    use quickcheck_macros::quickcheck;
    use std::collections::HashSet;

    #[test]
    fn test_3_different_values() {
        let original = vec![1, 2, 3];
        let res = permute(&original);
        assert_eq!(res.len(), 6); // 3!
        for permut in res {
            assert_valid_permutation(&original, &permut)
        }
    }

    #[test]
    fn test_3_times_the_same_value() {
        let original = vec![1, 1, 1];
        let res = permute(&original);
        assert_eq!(res.len(), 6); // 3!
        for permut in res {
            assert_valid_permutation(&original, &permut)
        }
    }

    #[quickcheck]
    fn test_some_elements(NotTooBigVec { inner: original }: NotTooBigVec) {
        let permutations = permute(&original);
        assert_permutations(&original, &permutations)
    }

    #[test]
    fn test_unique_values() {
        let original = vec![1, 1, 2, 2];
        let unique_permutations = permute_unique(&original);
        let every_permutation = permute(&original);
        for unique_permutation in &unique_permutations {
            assert!(every_permutation.contains(unique_permutation));
        }
        assert_eq!(
            unique_permutations.len(),
            every_permutation.iter().collect::<HashSet<_>>().len()
        )
    }
}


/// <https://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm>
pub fn steinhaus_johnson_trotter_permute<T: Clone>(array: &[T]) -> Vec<Vec<T>> {
    let len = array.len();
    let mut array = array.to_owned();
    let mut inversion_vector = vec![0; len];
    let mut i = 1;
    let mut res = Vec::with_capacity((1..=len).product());
    res.push(array.clone());
    while i < len {
        if inversion_vector[i] < i {
            if i % 2 == 0 {
                array.swap(0, i);
            } else {
                array.swap(inversion_vector[i], i);
            }
            res.push(array.to_vec());
            inversion_vector[i] += 1;
            i = 1;
        } else {
            inversion_vector[i] = 0;
            i += 1;
        }
    }
    res
}

#[cfg(test)]
mod tests {
    use quickcheck_macros::quickcheck;

    use crate::general::permutations::steinhaus_johnson_trotter::steinhaus_johnson_trotter_permute;
    use crate::general::permutations::tests::{
        assert_permutations, assert_valid_permutation, NotTooBigVec,
    };

    #[test]
    fn test_3_different_values() {
        let original = vec![1, 2, 3];
        let res = steinhaus_johnson_trotter_permute(&original);
        assert_eq!(res.len(), 6); // 3!
        for permut in res {
            assert_valid_permutation(&original, &permut)
        }
    }

    #[test]
    fn test_3_times_the_same_value() {
        let original = vec![1, 1, 1];
        let res = steinhaus_johnson_trotter_permute(&original);
        assert_eq!(res.len(), 6); // 3!
        for permut in res {
            assert_valid_permutation(&original, &permut)
        }
    }

    #[quickcheck]
    fn test_some_elements(NotTooBigVec { inner: original }: NotTooBigVec) {
        let permutations = steinhaus_johnson_trotter_permute(&original);
        assert_permutations(&original, &permutations)
    }
}


type Point = (f64, f64);
use std::cmp::Ordering;

fn point_cmp((a1, a2): &Point, (b1, b2): &Point) -> Ordering {
    let acmp = f64_cmp(a1, b1);
    match acmp {
        Ordering::Equal => f64_cmp(a2, b2),
        _ => acmp,
    }
}

fn f64_cmp(a: &f64, b: &f64) -> Ordering {
    a.partial_cmp(b).unwrap()
}

/// returns the two closest points
/// or None if there are zero or one point
pub fn closest_points(points: &[Point]) -> Option<(Point, Point)> {
    let mut points: Vec<Point> = points.to_vec();
    points.sort_by(point_cmp);

    closest_points_aux(&points, 0, points.len())
}

fn sqr_dist((x1, y1): &Point, (x2, y2): &Point) -> f64 {
    let dx = *x1 - *x2;
    let dy = *y1 - *y2;

    dx * dx + dy * dy
}

fn closest_points_aux(
    points: &[Point],
    mut start: usize,
    mut end: usize,
) -> Option<(Point, Point)> {
    let n = end - start;

    if n <= 1 {
        return None;
    }

    if n <= 3 {
        // bruteforce
        let mut min = sqr_dist(&points[0], &points[1]);
        let mut pair = (points[0], points[1]);

        for i in 1..n {
            for j in (i + 1)..n {
                let new = sqr_dist(&points[i], &points[j]);
                if new < min {
                    min = new;
                    pair = (points[i], points[j]);
                }
            }
        }
        return Some(pair);
    }

    let mid = (start + end) / 2;
    let left = closest_points_aux(points, start, mid);
    let right = closest_points_aux(points, mid, end);

    let (mut min_sqr_dist, mut pair) = match (left, right) {
        (Some((l1, l2)), Some((r1, r2))) => {
            let dl = sqr_dist(&l1, &l2);
            let dr = sqr_dist(&r1, &r2);
            if dl < dr {
                (dl, (l1, l2))
            } else {
                (dr, (r1, r2))
            }
        }
        (Some((a, b)), None) => (sqr_dist(&a, &b), (a, b)),
        (None, Some((a, b))) => (sqr_dist(&a, &b), (a, b)),
        (None, None) => unreachable!(),
    };

    let mid_x = points[mid].0;
    let dist = min_sqr_dist.sqrt();
    while points[start].0 < mid_x - dist {
        start += 1;
    }
    while points[end - 1].0 > mid_x + dist {
        end -= 1;
    }

    let mut mids: Vec<&Point> = points[start..end].iter().collect();
    mids.sort_by(|a, b| f64_cmp(&a.1, &b.1));

    for (i, e) in mids.iter().enumerate() {
        for k in 1..8 {
            if i + k >= mids.len() {
                break;
            }

            let new = sqr_dist(e, mids[i + k]);
            if new < min_sqr_dist {
                min_sqr_dist = new;
                pair = (**e, *mids[i + k]);
            }
        }
    }

    Some(pair)
}

#[cfg(test)]
mod tests {
    use super::closest_points;
    use super::Point;

    fn eq(p1: Option<(Point, Point)>, p2: Option<(Point, Point)>) -> bool {
        match (p1, p2) {
            (None, None) => true,
            (Some((p1, p2)), Some((p3, p4))) => (p1 == p3 && p2 == p4) || (p1 == p4 && p2 == p3),
            _ => false,
        }
    }

    macro_rules! assert_display {
        ($left: expr, $right: expr) => {
            assert!(
                eq($left, $right),
                "assertion failed: `(left == right)`\nleft: `{:?}`,\nright: `{:?}`",
                $left,
                $right
            )
        };
    }

    #[test]
    fn zero_points() {
        let vals: [Point; 0] = [];
        assert_display!(closest_points(&vals), None::<(Point, Point)>);
    }

    #[test]
    fn one_points() {
        let vals = [(0., 0.)];
        assert_display!(closest_points(&vals), None::<(Point, Point)>);
    }

    #[test]
    fn two_points() {
        let vals = [(0., 0.), (1., 1.)];
        assert_display!(closest_points(&vals), Some(((0., 0.), (1., 1.))));
    }

    #[test]
    fn three_points() {
        let vals = [(0., 0.), (1., 1.), (3., 3.)];
        assert_display!(closest_points(&vals), Some(((0., 0.), (1., 1.))));
    }

    #[test]
    fn list_1() {
        let vals = [
            (0., 0.),
            (2., 1.),
            (5., 2.),
            (2., 3.),
            (4., 0.),
            (0., 4.),
            (5., 6.),
            (4., 4.),
            (7., 3.),
            (-1., 2.),
            (2., 6.),
        ];
        assert_display!(closest_points(&vals), Some(((2., 1.), (2., 3.))));
    }

    #[test]
    fn list_2() {
        let vals = [
            (1., 3.),
            (4., 6.),
            (8., 8.),
            (7., 5.),
            (5., 3.),
            (10., 3.),
            (7., 1.),
            (8., 3.),
            (4., 9.),
            (4., 12.),
            (4., 15.),
            (7., 14.),
            (8., 12.),
            (6., 10.),
            (4., 14.),
            (2., 7.),
            (3., 8.),
            (5., 8.),
            (6., 7.),
            (8., 10.),
            (6., 12.),
        ];
        assert_display!(closest_points(&vals), Some(((4., 14.), (4., 15.))));
    }

    #[test]
    fn vertical_points() {
        let vals = [
            (0., 0.),
            (0., 50.),
            (0., -25.),
            (0., 40.),
            (0., 42.),
            (0., 100.),
            (0., 17.),
            (0., 29.),
            (0., -50.),
            (0., 37.),
            (0., 34.),
            (0., 8.),
            (0., 3.),
            (0., 46.),
        ];
        assert_display!(closest_points(&vals), Some(((0., 40.), (0., 42.))));
    }
}


mod closest_points;

pub use self::closest_points::closest_points;


use std::{
    collections::{BTreeMap, BinaryHeap},
    ops::Add,
};

use num_traits::Zero;

type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;

#[derive(Clone, Debug, Eq, PartialEq)]
struct Candidate<V, E> {
    estimated_weight: E,
    real_weight: E,
    state: V,
}

impl<V: Ord + Copy, E: Ord + Copy> PartialOrd for Candidate<V, E> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        // Note the inverted order; we want nodes with lesser weight to have
        // higher priority
        other.estimated_weight.partial_cmp(&self.estimated_weight)
    }
}

impl<V: Ord + Copy, E: Ord + Copy> Ord for Candidate<V, E> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        // Note the inverted order; we want nodes with lesser weight to have
        // higher priority
        other.estimated_weight.cmp(&self.estimated_weight)
    }
}

pub fn astar<V: Ord + Copy, E: Ord + Copy + Add<Output = E> + Zero>(
    graph: &Graph<V, E>,
    start: V,
    target: V,
    heuristic: impl Fn(V) -> E,
) -> Option<(E, Vec<V>)> {
    // traversal front
    let mut queue = BinaryHeap::new();
    // maps each node to its predecessor in the final path
    let mut previous = BTreeMap::new();
    // weights[v] is the accumulated weight from start to v
    let mut weights = BTreeMap::new();
    // initialize traversal
    weights.insert(start, E::zero());
    queue.push(Candidate {
        estimated_weight: heuristic(start),
        real_weight: E::zero(),
        state: start,
    });
    while let Some(Candidate {
        estimated_weight: _,
        real_weight,
        state: current,
    }) = queue.pop()
    {
        if current == target {
            break;
        }
        for (&next, &weight) in &graph[&current] {
            let real_weight = real_weight + weight;
            if weights
                .get(&next)
                .map(|&weight| real_weight < weight)
                .unwrap_or(true)
            {
                // current allows us to reach next with lower weight (or at all)
                // add next to the front
                let estimated_weight = real_weight + heuristic(next);
                weights.insert(next, real_weight);
                queue.push(Candidate {
                    estimated_weight,
                    real_weight,
                    state: next,
                });
                previous.insert(next, current);
            }
        }
    }
    let weight = if let Some(&weight) = weights.get(&target) {
        weight
    } else {
        // we did not reach target from start
        return None;
    };
    // build path in reverse
    let mut current = target;
    let mut path = vec![current];
    while current != start {
        let prev = previous
            .get(&current)
            .copied()
            .expect("We reached the target, but are unable to reconsistute the path");
        current = prev;
        path.push(current);
    }
    path.reverse();
    Some((weight, path))
}

#[cfg(test)]
mod tests {
    use super::{astar, Graph};
    use num_traits::Zero;
    use std::collections::BTreeMap;

    // the null heuristic make A* equivalent to Dijkstra
    fn null_heuristic<V, E: Zero>(_v: V) -> E {
        E::zero()
    }

    fn add_edge<V: Ord + Copy, E: Ord>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {
        graph.entry(v1).or_insert_with(BTreeMap::new).insert(v2, c);
        graph.entry(v2).or_insert_with(BTreeMap::new);
    }

    #[test]
    fn single_vertex() {
        let mut graph: Graph<usize, usize> = BTreeMap::new();
        graph.insert(0, BTreeMap::new());

        assert_eq!(astar(&graph, 0, 0, null_heuristic), Some((0, vec![0])));
        assert_eq!(astar(&graph, 0, 1, null_heuristic), None);
    }

    #[test]
    fn single_edge() {
        let mut graph = BTreeMap::new();
        add_edge(&mut graph, 0, 1, 2);

        assert_eq!(astar(&graph, 0, 1, null_heuristic), Some((2, vec![0, 1])));
        assert_eq!(astar(&graph, 1, 0, null_heuristic), None);
    }

    #[test]
    fn graph_1() {
        let mut graph = BTreeMap::new();
        add_edge(&mut graph, 'a', 'c', 12);
        add_edge(&mut graph, 'a', 'd', 60);
        add_edge(&mut graph, 'b', 'a', 10);
        add_edge(&mut graph, 'c', 'b', 20);
        add_edge(&mut graph, 'c', 'd', 32);
        add_edge(&mut graph, 'e', 'a', 7);

        // from a
        assert_eq!(
            astar(&graph, 'a', 'a', null_heuristic),
            Some((0, vec!['a']))
        );
        assert_eq!(
            astar(&graph, 'a', 'b', null_heuristic),
            Some((32, vec!['a', 'c', 'b']))
        );
        assert_eq!(
            astar(&graph, 'a', 'c', null_heuristic),
            Some((12, vec!['a', 'c']))
        );
        assert_eq!(
            astar(&graph, 'a', 'd', null_heuristic),
            Some((12 + 32, vec!['a', 'c', 'd']))
        );
        assert_eq!(astar(&graph, 'a', 'e', null_heuristic), None);

        // from b
        assert_eq!(
            astar(&graph, 'b', 'a', null_heuristic),
            Some((10, vec!['b', 'a']))
        );
        assert_eq!(
            astar(&graph, 'b', 'b', null_heuristic),
            Some((0, vec!['b']))
        );
        assert_eq!(
            astar(&graph, 'b', 'c', null_heuristic),
            Some((10 + 12, vec!['b', 'a', 'c']))
        );
        assert_eq!(
            astar(&graph, 'b', 'd', null_heuristic),
            Some((10 + 12 + 32, vec!['b', 'a', 'c', 'd']))
        );
        assert_eq!(astar(&graph, 'b', 'e', null_heuristic), None);

        // from c
        assert_eq!(
            astar(&graph, 'c', 'a', null_heuristic),
            Some((20 + 10, vec!['c', 'b', 'a']))
        );
        assert_eq!(
            astar(&graph, 'c', 'b', null_heuristic),
            Some((20, vec!['c', 'b']))
        );
        assert_eq!(
            astar(&graph, 'c', 'c', null_heuristic),
            Some((0, vec!['c']))
        );
        assert_eq!(
            astar(&graph, 'c', 'd', null_heuristic),
            Some((32, vec!['c', 'd']))
        );
        assert_eq!(astar(&graph, 'c', 'e', null_heuristic), None);

        // from d
        assert_eq!(astar(&graph, 'd', 'a', null_heuristic), None);
        assert_eq!(astar(&graph, 'd', 'b', null_heuristic), None);
        assert_eq!(astar(&graph, 'd', 'c', null_heuristic), None);
        assert_eq!(
            astar(&graph, 'd', 'd', null_heuristic),
            Some((0, vec!['d']))
        );
        assert_eq!(astar(&graph, 'd', 'e', null_heuristic), None);

        // from e
        assert_eq!(
            astar(&graph, 'e', 'a', null_heuristic),
            Some((7, vec!['e', 'a']))
        );
        assert_eq!(
            astar(&graph, 'e', 'b', null_heuristic),
            Some((7 + 12 + 20, vec!['e', 'a', 'c', 'b']))
        );
        assert_eq!(
            astar(&graph, 'e', 'c', null_heuristic),
            Some((7 + 12, vec!['e', 'a', 'c']))
        );
        assert_eq!(
            astar(&graph, 'e', 'd', null_heuristic),
            Some((7 + 12 + 32, vec!['e', 'a', 'c', 'd']))
        );
        assert_eq!(
            astar(&graph, 'e', 'e', null_heuristic),
            Some((0, vec!['e']))
        );
    }

    #[test]
    fn test_heuristic() {
        // make a grid
        let mut graph = BTreeMap::new();
        let rows = 100;
        let cols = 100;
        for row in 0..rows {
            for col in 0..cols {
                add_edge(&mut graph, (row, col), (row + 1, col), 1);
                add_edge(&mut graph, (row, col), (row, col + 1), 1);
                add_edge(&mut graph, (row, col), (row + 1, col + 1), 1);
                add_edge(&mut graph, (row + 1, col), (row, col), 1);
                add_edge(&mut graph, (row + 1, col + 1), (row, col), 1);
            }
        }

        // Dijkstra would explore most of the 101 Ã— 101 nodes
        // the heuristic should allow exploring only about 200 nodes
        let now = std::time::Instant::now();
        let res = astar(&graph, (0, 0), (100, 90), |(i, j)| 100 - i + 90 - j);
        assert!(now.elapsed() < std::time::Duration::from_millis(10));

        let (weight, path) = res.unwrap();
        assert_eq!(weight, 100);
        assert_eq!(path.len(), 101);
    }
}


use std::collections::BTreeMap;
use std::ops::Add;

use std::ops::Neg;

type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;

// performs the Bellman-Ford algorithm on the given graph from the given start
// the graph is an undirected graph
//
// if there is a negative weighted loop it returns None
// else it returns a map that for each reachable vertex associates the distance and the predecessor
// since the start has no predecessor but is reachable, map[start] will be None
pub fn bellman_ford<
    V: Ord + Copy,
    E: Ord + Copy + Add<Output = E> + Neg<Output = E> + std::ops::Sub<Output = E>,
>(
    graph: &Graph<V, E>,
    start: &V,
) -> Option<BTreeMap<V, Option<(V, E)>>> {
    let mut ans: BTreeMap<V, Option<(V, E)>> = BTreeMap::new();

    ans.insert(*start, None);

    for _ in 1..(graph.len()) {
        for (u, edges) in graph {
            let dist_u = match ans.get(u) {
                Some(Some((_, d))) => Some(*d),
                Some(None) => None,
                None => continue,
            };

            for (v, d) in edges {
                match ans.get(v) {
                    Some(Some((_, dist)))
                        // if this is a longer path, do nothing
                        if match dist_u {
                            Some(dist_u) => dist_u + *d >= *dist,
                            None => d >= dist,
                        } => {}
                    Some(None) => {
                        match dist_u {
                            // if dist_u + d < 0 there is a negative loop going by start
                            // else it's just a longer path
                            Some(dist_u) if dist_u >= -*d => {}
                            // negative self edge or negative loop
                            _ => {
                                if *d > *d + *d {
                                    return None;
                                }
                            }
                        };
                    }
                    // it's a shorter path: either dist_v was infinite or it was longer than dist_u + d
                    _ => {
                        ans.insert(
                            *v,
                            Some((
                                *u,
                                match dist_u {
                                    Some(dist) => dist + *d,
                                    None => *d,
                                },
                            )),
                        );
                    }
                }
            }
        }
    }

    for (u, edges) in graph {
        for (v, d) in edges {
            match (ans.get(u), ans.get(v)) {
                (Some(None), Some(None)) if *d > *d + *d => return None,
                (Some(None), Some(Some((_, dv)))) if d < dv => return None,
                (Some(Some((_, du))), Some(None)) if *du < -*d => return None,
                (Some(Some((_, du))), Some(Some((_, dv)))) if *du + *d < *dv => return None,
                (_, _) => {}
            }
        }
    }

    Some(ans)
}

#[cfg(test)]
mod tests {
    use super::{bellman_ford, Graph};
    use std::collections::BTreeMap;

    fn add_edge<V: Ord + Copy, E: Ord>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {
        graph.entry(v1).or_insert_with(BTreeMap::new).insert(v2, c);
        graph.entry(v2).or_insert_with(BTreeMap::new);
    }

    #[test]
    fn single_vertex() {
        let mut graph: Graph<isize, isize> = BTreeMap::new();
        graph.insert(0, BTreeMap::new());

        let mut dists = BTreeMap::new();
        dists.insert(0, None);

        assert_eq!(bellman_ford(&graph, &0), Some(dists));
    }

    #[test]
    fn single_edge() {
        let mut graph = BTreeMap::new();
        add_edge(&mut graph, 0, 1, 2);

        let mut dists_0 = BTreeMap::new();
        dists_0.insert(0, None);
        dists_0.insert(1, Some((0, 2)));

        assert_eq!(bellman_ford(&graph, &0), Some(dists_0));

        let mut dists_1 = BTreeMap::new();
        dists_1.insert(1, None);

        assert_eq!(bellman_ford(&graph, &1), Some(dists_1));
    }

    #[test]
    fn tree_1() {
        let mut graph = BTreeMap::new();
        let mut dists = BTreeMap::new();
        dists.insert(1, None);
        for i in 1..100 {
            add_edge(&mut graph, i, i * 2, i * 2);
            add_edge(&mut graph, i, i * 2 + 1, i * 2 + 1);

            match dists[&i] {
                Some((_, d)) => {
                    dists.insert(i * 2, Some((i, d + i * 2)));
                    dists.insert(i * 2 + 1, Some((i, d + i * 2 + 1)));
                }
                None => {
                    dists.insert(i * 2, Some((i, i * 2)));
                    dists.insert(i * 2 + 1, Some((i, i * 2 + 1)));
                }
            }
        }

        assert_eq!(bellman_ford(&graph, &1), Some(dists));
    }

    #[test]
    fn graph_1() {
        let mut graph = BTreeMap::new();
        add_edge(&mut graph, 'a', 'c', 12);
        add_edge(&mut graph, 'a', 'd', 60);
        add_edge(&mut graph, 'b', 'a', 10);
        add_edge(&mut graph, 'c', 'b', 20);
        add_edge(&mut graph, 'c', 'd', 32);
        add_edge(&mut graph, 'e', 'a', 7);

        let mut dists_a = BTreeMap::new();
        dists_a.insert('a', None);
        dists_a.insert('c', Some(('a', 12)));
        dists_a.insert('d', Some(('c', 44)));
        dists_a.insert('b', Some(('c', 32)));
        assert_eq!(bellman_ford(&graph, &'a'), Some(dists_a));

        let mut dists_b = BTreeMap::new();
        dists_b.insert('b', None);
        dists_b.insert('a', Some(('b', 10)));
        dists_b.insert('c', Some(('a', 22)));
        dists_b.insert('d', Some(('c', 54)));
        assert_eq!(bellman_ford(&graph, &'b'), Some(dists_b));

        let mut dists_c = BTreeMap::new();
        dists_c.insert('c', None);
        dists_c.insert('b', Some(('c', 20)));
        dists_c.insert('d', Some(('c', 32)));
        dists_c.insert('a', Some(('b', 30)));
        assert_eq!(bellman_ford(&graph, &'c'), Some(dists_c));

        let mut dists_d = BTreeMap::new();
        dists_d.insert('d', None);
        assert_eq!(bellman_ford(&graph, &'d'), Some(dists_d));

        let mut dists_e = BTreeMap::new();
        dists_e.insert('e', None);
        dists_e.insert('a', Some(('e', 7)));
        dists_e.insert('c', Some(('a', 19)));
        dists_e.insert('d', Some(('c', 51)));
        dists_e.insert('b', Some(('c', 39)));
        assert_eq!(bellman_ford(&graph, &'e'), Some(dists_e));
    }

    #[test]
    fn graph_2() {
        let mut graph = BTreeMap::new();
        add_edge(&mut graph, 0, 1, 6);
        add_edge(&mut graph, 0, 3, 7);
        add_edge(&mut graph, 1, 2, 5);
        add_edge(&mut graph, 1, 3, 8);
        add_edge(&mut graph, 1, 4, -4);
        add_edge(&mut graph, 2, 1, -2);
        add_edge(&mut graph, 3, 2, -3);
        add_edge(&mut graph, 3, 4, 9);
        add_edge(&mut graph, 4, 0, 3);
        add_edge(&mut graph, 4, 2, 7);

        let mut dists_0 = BTreeMap::new();
        dists_0.insert(0, None);
        dists_0.insert(1, Some((2, 2)));
        dists_0.insert(2, Some((3, 4)));
        dists_0.insert(3, Some((0, 7)));
        dists_0.insert(4, Some((1, -2)));
        assert_eq!(bellman_ford(&graph, &0), Some(dists_0));

        let mut dists_1 = BTreeMap::new();
        dists_1.insert(0, Some((4, -1)));
        dists_1.insert(1, None);
        dists_1.insert(2, Some((4, 3)));
        dists_1.insert(3, Some((0, 6)));
        dists_1.insert(4, Some((1, -4)));
        assert_eq!(bellman_ford(&graph, &1), Some(dists_1));

        let mut dists_2 = BTreeMap::new();
        dists_2.insert(0, Some((4, -3)));
        dists_2.insert(1, Some((2, -2)));
        dists_2.insert(2, None);
        dists_2.insert(3, Some((0, 4)));
        dists_2.insert(4, Some((1, -6)));
        assert_eq!(bellman_ford(&graph, &2), Some(dists_2));

        let mut dists_3 = BTreeMap::new();
        dists_3.insert(0, Some((4, -6)));
        dists_3.insert(1, Some((2, -5)));
        dists_3.insert(2, Some((3, -3)));
        dists_3.insert(3, None);
        dists_3.insert(4, Some((1, -9)));
        assert_eq!(bellman_ford(&graph, &3), Some(dists_3));

        let mut dists_4 = BTreeMap::new();
        dists_4.insert(0, Some((4, 3)));
        dists_4.insert(1, Some((2, 5)));
        dists_4.insert(2, Some((4, 7)));
        dists_4.insert(3, Some((0, 10)));
        dists_4.insert(4, None);
        assert_eq!(bellman_ford(&graph, &4), Some(dists_4));
    }

    #[test]
    fn graph_with_negative_loop() {
        let mut graph = BTreeMap::new();
        add_edge(&mut graph, 0, 1, 6);
        add_edge(&mut graph, 0, 3, 7);
        add_edge(&mut graph, 1, 2, 5);
        add_edge(&mut graph, 1, 3, 8);
        add_edge(&mut graph, 1, 4, -4);
        add_edge(&mut graph, 2, 1, -4);
        add_edge(&mut graph, 3, 2, -3);
        add_edge(&mut graph, 3, 4, 9);
        add_edge(&mut graph, 4, 0, 3);
        add_edge(&mut graph, 4, 2, 7);

        assert_eq!(bellman_ford(&graph, &0), None);
        assert_eq!(bellman_ford(&graph, &1), None);
        assert_eq!(bellman_ford(&graph, &2), None);
        assert_eq!(bellman_ford(&graph, &3), None);
        assert_eq!(bellman_ford(&graph, &4), None);
    }
}