use std::fmt::Debug;
use dicetest::hint_section;
use crate::{
Elem, Fun1, Fun2, Vars,
props::binop::{associative, commutative, distributive, identity_elem, inverse_elem},
};
pub fn semigroup<S, O>(vars: Vars<S, 3>, op: Fun2<O>)
where
S: Debug + Clone + PartialEq,
O: Fn(S, S) -> S,
{
hint_section!("Is `({}, {})` a semigroup?", vars.set, op.name);
associative(vars, op);
}
pub fn monoid<S, O>(vars: Vars<S, 3>, op: Fun2<O>, e: Elem<S>)
where
S: Debug + Clone + PartialEq,
O: Fn(S, S) -> S,
{
hint_section!("Is `({}, {}, {})` a monoid?", vars.set, op.name, e.name,);
let [a, b, c] = vars.elems;
let vars_1 = Vars::new(vars.set, [a.clone()]);
let vars_3 = Vars::new(vars.set, [a, b, c]);
semigroup(vars_3, op.as_ref());
identity_elem(vars_1, op, e)
}
pub fn group<S, O, I>(vars: Vars<S, 3>, op: Fun2<O>, inv: Fun1<I>, e: Elem<S>)
where
S: Debug + Clone + PartialEq,
O: Fn(S, S) -> S,
I: Fn(S) -> S,
{
hint_section!(
"Is `({}, {}, {}, {})` a group?",
vars.set,
op.name,
inv.name,
e.name,
);
let [a, b, c] = vars.elems;
let vars_2 = Vars::new(vars.set, [a.clone(), b.clone()]);
let vars_3 = Vars::new(vars.set, [a, b, c]);
monoid(vars_3, op.as_ref(), e);
inverse_elem(vars_2, op, inv);
}
pub fn abelian_group<S, O, I>(vars: Vars<S, 3>, op: Fun2<O>, inv: Fun1<I>, e: Elem<S>)
where
S: Debug + Clone + PartialEq,
O: Fn(S, S) -> S,
I: Fn(S) -> S,
{
hint_section!(
"Is `({}, {}, {}, {})` an abelian group?",
vars.set,
op.name,
inv.name,
e.name,
);
let [a, b, c] = vars.elems;
let vars_2 = Vars::new(vars.set, [a.clone(), b.clone()]);
let vars_3 = Vars::new(vars.set, [a, b, c]);
group(vars_3, op.as_ref(), inv, e);
commutative(vars_2, op);
}
pub fn ring<S, A, N, M>(
vars: Vars<S, 3>,
add: Fun2<A>,
mul: Fun2<M>,
neg: Fun1<N>,
zero: Elem<S>,
one: Elem<S>,
) where
S: Debug + Clone + PartialEq,
A: Fn(S, S) -> S,
M: Fn(S, S) -> S,
N: Fn(S) -> S,
{
hint_section!(
"Is `({}, {}, {}, {}, {}, {})` a ring?",
vars.set,
add.name,
mul.name,
neg.name,
zero.name,
one.name,
);
abelian_group(vars.clone(), add.as_ref(), neg, zero);
monoid(vars.clone(), mul.as_ref(), one);
distributive(vars, add, mul);
}
pub fn commutative_ring<S, A, M, N>(
vars: Vars<S, 3>,
add: Fun2<A>,
mul: Fun2<M>,
neg: Fun1<N>,
zero: Elem<S>,
one: Elem<S>,
) where
S: Debug + Clone + PartialEq,
A: Fn(S, S) -> S,
M: Fn(S, S) -> S,
N: Fn(S) -> S,
{
hint_section!(
"Is `({}, {}, {}, {}, {}, {})` a commutative ring?",
vars.set,
add.name,
mul.name,
neg.name,
zero.name,
one.name,
);
let [a, b, c] = vars.elems;
let vars_2 = Vars::new(vars.set, [a.clone(), b.clone()]);
let vars_3 = Vars::new(vars.set, [a, b, c]);
ring(vars_3, add, mul.as_ref(), neg, zero, one);
commutative(vars_2, mul);
}
#[allow(clippy::too_many_arguments)]
pub fn field<S, A, M, N, I>(
vars: Vars<S, 3>,
non_zero_vars: Vars<S, 2>,
add: Fun2<A>,
mul: Fun2<M>,
neg: Fun1<N>,
inv: Fun1<I>,
zero: Elem<S>,
one: Elem<S>,
) where
S: Debug + Clone + PartialEq,
A: Fn(S, S) -> S,
M: Fn(S, S) -> S,
N: Fn(S) -> S,
I: Fn(S) -> S,
{
hint_section!(
"Is `({}, {}, {}, {}, {}, {}, {})` a field?",
vars.set,
add.name,
mul.name,
neg.name,
inv.name,
zero.name,
one.name,
);
commutative_ring(vars, add, mul.as_ref(), neg, zero, one);
inverse_elem(non_zero_vars, mul, inv);
}
#[cfg(test)]
mod tests {
use dicetest::prelude::*;
use crate::{Elem, Fun1, Fun2, Set, props};
#[test]
fn semigroup_example() {
Dicetest::once().run(|mut fate| {
let set = Set::new("u64", dice::u64(..=1000));
let vars = fate.roll(set.vars(["x", "y", "z"]));
let op = Fun2::infix("+", |x, y| x + y);
props::algebra::semigroup(vars, op);
})
}
#[test]
fn monoid_example() {
Dicetest::once().run(|mut fate| {
let set = Set::new("u64", dice::u64(..=1000));
let vars = fate.roll(set.vars(["x", "y", "z"]));
let op = Fun2::infix("+", |x, y| x + y);
let e = Elem::new("zero", 0);
props::algebra::monoid(vars, op, e);
})
}
#[test]
fn group_example() {
Dicetest::once().run(|mut fate| {
let set = Set::new("i64", dice::i64(-1000..=1000));
let vars = fate.roll(set.vars(["x", "y", "z"]));
let op = Fun2::infix("+", |x, y| x + y);
let inv = Fun1::new("-", |x: i64| -x);
let e = Elem::new("zero", 0);
props::algebra::group(vars, op, inv, e);
})
}
#[test]
fn abelian_group_example() {
Dicetest::once().run(|mut fate| {
let set = Set::new("i64", dice::i64(-1000..=1000));
let vars = fate.roll(set.vars(["x", "y", "z"]));
let op = Fun2::infix("+", |x, y| x + y);
let inv = Fun1::new("-", |x: i64| -x);
let e = Elem::new("zero", 0);
props::algebra::abelian_group(vars, op, inv, e);
})
}
#[test]
fn ring_example() {
Dicetest::once().run(|mut fate| {
let set = Set::new("i64", dice::i64(-1000..=1000));
let vars = fate.roll(set.vars(["x", "y", "z"]));
let add = Fun2::infix("+", |x, y| x + y);
let mul = Fun2::infix("*", |x, y| x * y);
let neg = Fun1::new("-", |x: i64| -x);
let zero = Elem::new("zero", 0);
let one = Elem::new("one", 1);
props::algebra::ring(vars, add, mul, neg, zero, one);
})
}
#[test]
fn commutative_ring_example() {
Dicetest::once().run(|mut fate| {
let set = Set::new("i64", dice::i64(-1000..=1000));
let vars = fate.roll(set.vars(["x", "y", "z"]));
let add = Fun2::infix("+", |x, y| x + y);
let mul = Fun2::infix("*", |x, y| x * y);
let neg = Fun1::new("-", |x: i64| -x);
let zero = Elem::new("zero", 0);
let one = Elem::new("one", 1);
props::algebra::commutative_ring(vars, add, mul, neg, zero, one);
})
}
#[test]
fn field_example() {
}
}