(x: &[f64], y: &[f64], n_bins: usize)
| 79 | } |
| 80 | |
| 81 | fn histogram2d(x: &[f64], y: &[f64], n_bins: usize) -> CodependenceResult<Vec<Vec<usize>>> { |
| 82 | if x.len() != y.len() { |
| 83 | return Err(CodependenceError::InputLengthMismatch); |
| 84 | } |
| 85 | if n_bins == 0 { |
| 86 | return Err(CodependenceError::InvalidBins); |
| 87 | } |
| 88 | |
| 89 | let mut min_x = f64::INFINITY; |
| 90 | let mut max_x = f64::NEG_INFINITY; |
| 91 | let mut min_y = f64::INFINITY; |
| 92 | let mut max_y = f64::NEG_INFINITY; |
| 93 | |
| 94 | for (&xi, &yi) in x.iter().zip(y.iter()) { |
| 95 | if xi < min_x { |
| 96 | min_x = xi; |
| 97 | } |
| 98 | if xi > max_x { |
| 99 | max_x = xi; |
| 100 | } |
| 101 | if yi < min_y { |
| 102 | min_y = yi; |
| 103 | } |
| 104 | if yi > max_y { |
| 105 | max_y = yi; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | let mut counts = vec![vec![0usize; n_bins]; n_bins]; |
| 110 | if (max_x - min_x).abs() < f64::EPSILON || (max_y - min_y).abs() < f64::EPSILON { |
| 111 | for _ in 0..x.len() { |
| 112 | counts[n_bins - 1][n_bins - 1] += 1; |
| 113 | } |
| 114 | return Ok(counts); |
| 115 | } |
| 116 | |
| 117 | let bin_width_x = (max_x - min_x) / n_bins as f64; |
| 118 | let bin_width_y = (max_y - min_y) / n_bins as f64; |
| 119 | |
| 120 | for (&xi, &yi) in x.iter().zip(y.iter()) { |
| 121 | let mut ix = ((xi - min_x) / bin_width_x).floor() as isize; |
| 122 | let mut iy = ((yi - min_y) / bin_width_y).floor() as isize; |
| 123 | if ix < 0 { |
| 124 | ix = 0; |
| 125 | } |
| 126 | if iy < 0 { |
| 127 | iy = 0; |
| 128 | } |
| 129 | if ix as usize >= n_bins { |
| 130 | ix = (n_bins as isize) - 1; |
| 131 | } |
| 132 | if iy as usize >= n_bins { |
| 133 | iy = (n_bins as isize) - 1; |
| 134 | } |
| 135 | counts[ix as usize][iy as usize] += 1; |
| 136 | } |
| 137 | |
| 138 | Ok(counts) |
no test coverage detected