use crate::errors::AlkahestError;
use crate::ffield::FiniteFieldError;
use crate::group::GroupError;
use crate::numfield::NumberFieldError;
use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum CharacterError {
Group(GroupError),
Field(NumberFieldError),
LinearAlgebra(FiniteFieldError),
OrderTooLarge {
order: String,
cap: u64,
},
CapTooLarge {
cap: u64,
max: u64,
},
ExponentFieldTooLarge {
exponent: u64,
degree: usize,
max: usize,
},
NoSuitablePrime {
exponent: u64,
order: String,
searched_to: u64,
},
NotAMember {
element: String,
},
ClassIndexOutOfRange {
index: usize,
classes: usize,
},
SelfCheckFailed {
check: &'static str,
detail: String,
},
SplittingIncomplete {
found: usize,
classes: usize,
},
Internal {
detail: String,
},
}
impl From<GroupError> for CharacterError {
fn from(e: GroupError) -> Self {
CharacterError::Group(e)
}
}
impl From<NumberFieldError> for CharacterError {
fn from(e: NumberFieldError) -> Self {
CharacterError::Field(e)
}
}
impl From<FiniteFieldError> for CharacterError {
fn from(e: FiniteFieldError) -> Self {
CharacterError::LinearAlgebra(e)
}
}
impl fmt::Display for CharacterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CharacterError::Group(e) => write!(f, "{e}"),
CharacterError::Field(e) => write!(f, "{e}"),
CharacterError::LinearAlgebra(e) => write!(f, "{e}"),
CharacterError::OrderTooLarge { order, cap } => write!(
f,
"the group has order {order}, above the conjugacy-class enumeration cap of \
{cap}; classes here are found by conjugating every element, so its order is \
known exactly but its classes will not be listed"
),
CharacterError::CapTooLarge { cap, max } => write!(
f,
"a conjugacy-class cap of {cap} is above the hard ceiling of {max}"
),
CharacterError::ExponentFieldTooLarge {
exponent,
degree,
max,
} => write!(
f,
"exp G = {exponent}, so character values live in Q(zeta_{exponent}) of degree \
phi({exponent}) = {degree}, above this module's ceiling of {max}"
),
CharacterError::NoSuitablePrime {
exponent,
order,
searched_to,
} => write!(
f,
"no prime p = 1 (mod {exponent}) with p > {order} was found at or below \
{searched_to}"
),
CharacterError::NotAMember { element } => {
write!(f, "{element} is not an element of this group")
}
CharacterError::ClassIndexOutOfRange { index, classes } => write!(
f,
"class index {index} is out of range: this group has {classes} conjugacy classes"
),
CharacterError::SelfCheckFailed { check, detail } => write!(
f,
"the computed result failed its own {check} check and was withheld: {detail}"
),
CharacterError::SplittingIncomplete { found, classes } => write!(
f,
"the class multiplication matrices split the space into {found} common \
eigenspaces, not the {classes} required"
),
CharacterError::Internal { detail } => {
write!(f, "internal character-table invariant violated: {detail}")
}
}
}
}
impl std::error::Error for CharacterError {}
impl AlkahestError for CharacterError {
fn code(&self) -> &'static str {
match self {
CharacterError::Group(e) => e.code(),
CharacterError::Field(e) => e.code(),
CharacterError::LinearAlgebra(e) => e.code(),
CharacterError::OrderTooLarge { .. } => "E-CHAR-001",
CharacterError::CapTooLarge { .. } => "E-CHAR-002",
CharacterError::ExponentFieldTooLarge { .. } => "E-CHAR-003",
CharacterError::NoSuitablePrime { .. } => "E-CHAR-004",
CharacterError::NotAMember { .. } => "E-CHAR-005",
CharacterError::ClassIndexOutOfRange { .. } => "E-CHAR-006",
CharacterError::SelfCheckFailed { .. } => "E-CHAR-007",
CharacterError::SplittingIncomplete { .. } => "E-CHAR-008",
CharacterError::Internal { .. } => "E-CHAR-009",
}
}
fn remediation(&self) -> Option<&'static str> {
match self {
CharacterError::Group(e) => e.remediation(),
CharacterError::Field(e) => e.remediation(),
CharacterError::LinearAlgebra(e) => e.remediation(),
CharacterError::OrderTooLarge { .. } => Some(
"use `order()` and the stabilizer chain instead, or raise the cap with \
`ConjugacyClasses::of_with_cap` if |G| elements really fit in memory; there is \
no partial class partition on offer",
),
CharacterError::CapTooLarge { .. } => Some(
"the ceiling bounds memory, not patience: the class lookup holds one degree-n \
images array per group element. Work with a smaller group, or with a quotient \
or subgroup whose table you actually need",
),
CharacterError::ExponentFieldTooLarge { .. } => Some(
"exp G drives the field, so a large cyclic factor is the usual cause; the cap \
is on phi(exp G) and not on |G| at all, so a group of small exponent passes \
this ceiling at any order and meets the |G| cap instead, while a cyclic \
group of order 1000 is refused here despite being small",
),
CharacterError::NoSuitablePrime { .. } => Some(
"this is a search-bound miss rather than a mathematical obstruction — \
Dirichlet guarantees such a prime exists; report the group as a bug",
),
CharacterError::NotAMember { .. } => Some(
"test with `PermutationGroup::contains` first; note that points are 0-based \
here and composition is left-to-right, so a generator transcribed from GAP \
needs `Permutation::from_cycles_one_based`",
),
CharacterError::ClassIndexOutOfRange { .. } => {
Some("class indices run over 0..len(), with class 0 always the identity class")
}
CharacterError::SelfCheckFailed { .. } => Some(
"this is a defect in alkahest, not in the input: the orthogonality relations \
are implied by the group axioms, so a violation means the table is wrong. \
Report the generators as a minimal failing example",
),
CharacterError::SplittingIncomplete { .. } => Some(
"report the generators as a minimal failing example; with p prime to |G| and \
p = 1 mod exp G the class algebra is split semisimple, so this cannot happen \
for a correct implementation",
),
CharacterError::Internal { .. } => {
Some("report the generators as a minimal failing example")
}
}
}
}