Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v.
2.
0. If a copy of the MPL was not distributed with this
* file, You can obtain one at
http://mozilla.org/MPL/2.
0/. */
use std::cmp::min;
/// An Equation\<W\> is a representation of a GF(
2) linear functional
/// a(x) = b + sum_i a_i x_i
/// where a_i is equal to zero except for i in a block of
64*W coefficients
/// starting at i=s. We say an Equation is /aligned/ if a_s =
1.
/// (Note: a_i above denotes the i-th bit, not the i'th
64-bit limb.)
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Equation<const W: usize> {
pub s: usize, // the row number
pub a: [u64; W], // the non-trivial columns
pub b: u8, // the constant term
}
impl<const W: usize> Equation<W> {
/// Construct the equation a(x) = sum_{i=s}^{s+
64*W} a_i x^i.
/// The result is aligned.
pub fn homogeneous(s: usize, a: [u64; W]) -> Equation<W> {
Equation::inhomogeneous(s, a,
0)
}
/// Construct the equation a(x) = b + sum_{i=s}^{s+
64*W} a_i x^i.
/// The result is aligned.
pub fn inhomogeneous(s: usize, a: [u64; W], b: u8) -> Equation<W> {
let mut eq = Equation { s:
0, a, b };
eq.add(&Equation::zero());
eq.s += s;
eq
}
/// Construct the equation a(x) =
0.
pub fn zero() -> Self {
Equation {
s:
0,
a: [
0u64; W],
b:
0,
}
}
/// Is this a(x) =
1 or a(x) =
0?
pub fn is_zero(&self) -> bool {
// TODO: is_const? or maybe this gets the point across.
self.a == [
0u64; W]
}
/// Adds `other` into `self`, i.e. sets self.a ^= other.a and self.b ^= other.b and then aligns
/// the result.
pub fn add(&mut self, other: &Equation<W>) {
assert!(self.s == other.s);
// Add the equations in GF(
2)
for i in
0..W {
self.a[i] ^= other.a[i];
}
self.b ^= other.b;
// Exit early if this equation is now zero.
if self.is_zero() {
return;
}
// Shift until there is a non-zero bit in the lowest limb.
while self.a[
0] ==
0 {
self.a.rotate_left(
1);
}
// Shift first non-zero bit to position
0.
let k = self.a[
0].trailing_zeros();
if k ==
0 {
return;
}
for i in
0..W -
1 {
self.a[i] >>= k;
self.a[i] |= self.a[i +
1] << (
64 - k);
}
self.a[W -
1] >>= k;
// Update the starting position
self.s += k as usize;
}
/// Computes a(z) = sum a_i z_i.
pub fn eval(&self, z: &[u64]) -> u8 {
// Compute a(z), noting that this only depends
// on
64*W bits of z starting from position s.
let limb = self.s /
64;
let shift = self.s %
64;
let mut r =
0;
for i in limb..min(z.len(), limb + W) {
let mut tmp = z[i] >> shift;
if i +
1 < z.len() && shift !=
0 {
tmp |= z[i +
1] << (
64 - shift);
}
r ^= tmp & self.a[i - limb];
}
(r.count_ones() &
1) as u8
}
}
#[cfg(test)]
mod tests {
use crate::Equation;
#[test]
fn test_equation_add() {
let mut e1 = Equation {
s:
127,
a: [
0b11],
b:
1,
};
let e2 = Equation {
s:
127,
a: [
0b01],
b:
1,
};
e1.add(&e2);
// test that shifting works
assert!(e1.s ==
128);
assert!(e1.a[
0] ==
0b1);
assert!(e1.b ==
0);
let mut e1 = Equation {
s:
127,
a: [
0b11,
0b1110,
0b1,
0],
b:
1,
};
let e2 = Equation {
s:
127,
a: [
0b01,
0b0100,
0b0,
0],
b:
1,
};
e1.add(&e2);
// test that shifting works
assert!(e1.s ==
128);
assert!(e1.a[
0] ==
0b1);
// test that bits move between limbs
assert!(e1.a[
1] == (
1 <<
63) |
0b101);
assert!(e1.a[
2] ==
0);
assert!(e1.a[
3] ==
0);
assert!(e1.b ==
0);
}
#[test]
fn test_equation_eval() {
for s in
0..
64 {
let eq = Equation {
s,
a: [
0xffffffffffffffff,
0,
0,
0],
b:
0,
};
assert!(
0 == eq.eval(&[]));
for i in
0..
64 {
assert!(((i >= eq.s) as u8) == eq.eval(&[
1 << i,
0]));
assert!(((i < eq.s) as u8) == eq.eval(&[
0,
1 << i]));
assert!(
0 == eq.eval(&[
0,
0,
1 << i]));
}
}
}
}