///|
/// Cross recurrence does not assume synchronized clocks or exclude a diagonal.
pub fn cross_recurrence(
a : Trajectory,
b : Trajectory,
threshold : Double,
metric : Metric,
max_cells : Int32,
) -> Result[Recurrence, RqaError] {
if a.dimensions != b.dimensions {
return Err(Invalid("cross coordinate dimensions"))
}
if !finite(threshold) || threshold < 0.0 {
return Err(Invalid("cross threshold"))
}
if !cell_budget(a.samples, b.samples, max_cells) {
return Err(Limit("cross recurrence cell budget"))
}
let size = a.samples * b.samples
Ok({
height: a.samples,
width: b.samples,
mask: Array::make(size, true),
bits: Array::makei(size, fn(p) {
point_distance(a, p / b.samples, b, p % b.samples, metric) <= threshold
}),
})
}
///|
/// Restrict aligned indices in any matrix. Excluded cells split line structures.
pub fn Recurrence::exclude_band(
self : Recurrence,
width : Int32,
) -> Result[Recurrence, RqaError] {
if width < 0 || width > 4096 {
return Err(Invalid("exclusion band"))
}
let mask = Array::makei(self.bits.length(), fn(p) {
self.mask[p] && (p / self.width - p % self.width).abs() > width
})
let bits = Array::makei(self.bits.length(), fn(p) { mask[p] && self.bits[p] })
Ok({ height: self.height, width: self.width, bits, mask, })
}
///|
pub fn Recurrence::transpose(self : Recurrence) -> Recurrence {
let bits = Array::makei(self.bits.length(), fn(p) {
self.bits[p % self.height * self.width + p / self.height]
})
let mask = Array::makei(self.mask.length(), fn(p) {
self.mask[p % self.height * self.width + p / self.height]
})
{ height: self.width, width: self.height, bits, mask, }
}