///|
pub(all) struct Agreement {
  both : Int32
  only_first : Int32
  only_second : Int32
  neither : Int32
  common_eligible : Int32
  jaccard : Double?
  first_given_second : Double?
  second_given_first : Double?
} derive(Debug, Eq)

///|
pub extend Agreement with @debug.Debug::{to_repr}

///|
pub extend Agreement with Eq::{equal, not_equal}

///|
/// Compare only cells eligible in both matrices. Empty unions have undefined Jaccard.
/// These are descriptive conditional fractions, not significance or causality tests.
pub fn recurrence_agreement(
  first : Recurrence,
  second : Recurrence,
) -> Result[Agreement, RqaError] {
  if first.shape() != second.shape() {
    return Err(Invalid("agreement shape mismatch"))
  }
  let mut both = 0
  let mut only_first = 0
  let mut only_second = 0
  let mut neither = 0
  for p in 0.. Result[Recurrence, RqaError] {
  if matrices.length() < 1 || matrices.length() > 64 {
    return Err(Invalid("union matrix count"))
  }
  let first = matrices[0]
  let bits = Array::make(first.bits.length(), false)
  let mask = first.mask.copy()
  for r in matrices {
    if r.shape() != first.shape() {
      return Err(Invalid("union shape mismatch"))
    }
    for p in 0..