///|
/// Additive identity. Implementations used in Fenwick trees must form an abelian group.
pub(open) trait Zero {
  fn zero() -> Self
}

///|
/// Signed capacity/cost types supported by flow algorithms.
pub trait FlowInt {
  fn to_i64(Self) -> Int64
  fn from_i64(Int64) -> Self
  fn maximum() -> Int64
}

///|
/// Lossless modular reduction of the four ACL integer types.
pub trait ModInput {
  fn reduce(Self, Int) -> Int
  fn from_residue(Int) -> Self
}

///|
pub impl Zero for Int with fn zero() {
  0
}

///|
pub impl FlowInt for Int with fn to_i64(self) {
  self.to_int64()
}

///|
pub impl FlowInt for Int with fn from_i64(x) {
  x.to_int()
}

///|
pub impl FlowInt for Int with fn maximum() {
  2147483647L
}

///|
pub impl ModInput for Int with fn reduce(self, m) {
  let r = self.to_int64() % m.to_int64()
  (if r < 0L { r + m.to_int64() } else { r }).to_int()
}

///|
pub impl ModInput for Int with fn from_residue(x) {
  x
}

///|
pub impl Zero for Int64 with fn zero() {
  0L
}

///|
pub impl FlowInt for Int64 with fn to_i64(self) {
  self
}

///|
pub impl FlowInt for Int64 with fn from_i64(x) {
  x
}

///|
pub impl FlowInt for Int64 with fn maximum() {
  9223372036854775807L
}

///|
pub impl ModInput for Int64 with fn reduce(self, m) {
  let r = self % m.to_int64()
  (if r < 0L { r + m.to_int64() } else { r }).to_int()
}

///|
pub impl ModInput for Int64 with fn from_residue(x) {
  x.to_int64()
}

///|
pub impl Zero for UInt with fn zero() {
  0U
}

///|
pub impl ModInput for UInt with fn reduce(self, m) {
  (self.to_uint64() % m.to_uint64()).to_int()
}

///|
pub impl ModInput for UInt with fn from_residue(x) {
  x.reinterpret_as_uint()
}

///|
pub impl Zero for UInt64 with fn zero() {
  0UL
}

///|
pub impl ModInput for UInt64 with fn reduce(self, m) {
  (self % m.to_uint64()).to_int()
}

///|
pub impl ModInput for UInt64 with fn from_residue(x) {
  x.to_uint64()
}