Merge branch 'main' of ssh://git.chaboissier.fr:222/octagonal/picolog

This commit is contained in:
2026-02-12 21:00:15 +01:00
8 changed files with 454 additions and 0 deletions

1
doz/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

7
doz/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "doz"
version = "0.1.0"

6
doz/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "doz"
version = "0.1.0"
edition = "2024"
[dependencies]

254
doz/src/domain.rs Normal file
View File

@ -0,0 +1,254 @@
pub mod simple_range;
pub mod union;
use std::fmt::Display;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeTo;
pub struct Domain
{
pub ranges: Vec<DomainRange>,
}
/// Represents the set
/// $$\{x \in [\text{start}; \text{end}[ | x \equiv \text{congruent} \text{mod} \text{modulo}}$$
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DomainRange
{
pub start: LowerBound,
pub end: HigherBound,
pub modulo: u64,
pub congruent: i64,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct SimpleRange
{
pub start: LowerBound,
pub end: HigherBound,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum LowerBound
{
Infinity,
Bounded(i64),
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum HigherBound
{
Infinity,
Bounded(i64),
}
pub enum UnionResult<T>
{
Single(T),
Union(T, T),
}
impl Domain
{
pub fn empty(&self) -> Domain
{
Domain { ranges: vec![] }
}
pub fn is_empty(&self) -> bool
{
self.ranges.is_empty()
}
}
impl DomainRange
{
pub fn range(from: LowerBound, to: HigherBound) -> DomainRange
{
DomainRange {
start: from,
end: to,
modulo: 1,
congruent: 0,
}
}
pub fn is_simple(&self) -> Option<SimpleRange>
{
if self.modulo <= 1
{
Some(SimpleRange {
start: self.start,
end: self.end,
})
}
else
{
None
}
}
}
impl From<Range<i64>> for Domain
{
fn from(value: Range<i64>) -> Self
{
Domain {
ranges: vec![value.into()],
}
}
}
impl From<RangeTo<i64>> for Domain
{
fn from(value: RangeTo<i64>) -> Self
{
Domain {
ranges: vec![value.into()],
}
}
}
impl From<RangeFrom<i64>> for Domain
{
fn from(value: RangeFrom<i64>) -> Self
{
Domain {
ranges: vec![value.into()],
}
}
}
impl From<Range<i64>> for DomainRange
{
fn from(value: Range<i64>) -> Self
{
DomainRange::range(
LowerBound::Bounded(value.start),
HigherBound::Bounded(value.end),
)
}
}
impl From<RangeTo<i64>> for DomainRange
{
fn from(value: RangeTo<i64>) -> Self
{
DomainRange::range(LowerBound::Infinity, HigherBound::Bounded(value.end))
}
}
impl From<RangeFrom<i64>> for DomainRange
{
fn from(value: RangeFrom<i64>) -> Self
{
DomainRange::range(LowerBound::Bounded(value.start), HigherBound::Infinity)
}
}
impl Display for LowerBound
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
LowerBound::Infinity => write!(f, "-∞"),
LowerBound::Bounded(x) => write!(f, "{}", x),
}
}
}
impl Display for HigherBound
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
HigherBound::Infinity => write!(f, "+∞"),
HigherBound::Bounded(x) => write!(f, "{}", x),
}
}
}
impl Display for DomainRange
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "{}..{}", self.start, self.end)?;
if self.modulo > 1
{
write!(f, " ≡ {} [{}]", self.congruent, self.modulo)?;
}
Ok(())
}
}
impl Display for Domain
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
if self.is_empty()
{
write!(f, "Ø")
}
else
{
let len = self.ranges.len();
for (i, r) in self.ranges.iter().enumerate()
{
write!(f, "{}", r)?;
if i != len - 1
{
write!(f, " ")?;
}
}
Ok(())
}
}
}
impl PartialOrd for LowerBound
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>
{
Some(self.cmp(other))
}
}
impl Ord for LowerBound
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering
{
match (self, other)
{
(LowerBound::Infinity, LowerBound::Infinity) => std::cmp::Ordering::Equal,
(LowerBound::Infinity, LowerBound::Bounded(_)) => std::cmp::Ordering::Less,
(LowerBound::Bounded(_), LowerBound::Infinity) => std::cmp::Ordering::Greater,
(LowerBound::Bounded(a), LowerBound::Bounded(b)) => a.cmp(b),
}
}
}
impl PartialOrd for HigherBound
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>
{
Some(self.cmp(other))
}
}
impl Ord for HigherBound
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering
{
match (self, other)
{
(HigherBound::Infinity, HigherBound::Infinity) => std::cmp::Ordering::Equal,
(HigherBound::Infinity, HigherBound::Bounded(_)) => std::cmp::Ordering::Greater,
(HigherBound::Bounded(_), HigherBound::Infinity) => std::cmp::Ordering::Less,
(HigherBound::Bounded(a), HigherBound::Bounded(b)) => a.cmp(b),
}
}
}

View File

@ -0,0 +1,153 @@
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
use crate::domain::HigherBound;
use crate::domain::LowerBound;
use crate::domain::SimpleRange;
use crate::domain::UnionResult;
impl SimpleRange
{
pub fn union(&self, range: &SimpleRange) -> UnionResult<SimpleRange>
{
let (a, b) = (self.min_by_start(range), self.max_by_start(range));
match (a.end, b.start)
{
(HigherBound::Infinity, LowerBound::Infinity) =>
{
UnionResult::Single(SimpleRange::from(..))
}
(HigherBound::Infinity, LowerBound::Bounded(_)) => UnionResult::Single(SimpleRange {
start: a.start,
end: HigherBound::Infinity,
}),
(HigherBound::Bounded(_), LowerBound::Infinity) => UnionResult::Single(SimpleRange {
start: LowerBound::Infinity,
end: b.end,
}),
(HigherBound::Bounded(c), LowerBound::Bounded(d)) if c < d => UnionResult::Union(a, b),
(HigherBound::Bounded(_), LowerBound::Bounded(_)) => UnionResult::Single(SimpleRange {
start: a.start,
end: b.end,
}),
}
}
pub fn intersection(&self, range: &SimpleRange) -> Option<SimpleRange>
{
let (a, b) = (self.min_by_start(range), self.max_by_start(range));
match (a.end, b.start)
{
(HigherBound::Infinity, LowerBound::Infinity) => Some(SimpleRange::from(..)),
(HigherBound::Infinity, LowerBound::Bounded(a)) => Some(SimpleRange::from(a..)),
(HigherBound::Bounded(a), LowerBound::Infinity) => Some(SimpleRange::from(..a)),
(HigherBound::Bounded(a), LowerBound::Bounded(b)) if a <= b => None,
(HigherBound::Bounded(a), LowerBound::Bounded(b)) => Some(SimpleRange::from(a..b)),
}
}
pub fn without(&self, range: &SimpleRange) -> SimpleRange
{
match self.intersection(range)
{
Some(intersecting_part) => match self.union(&intersecting_part)
{
UnionResult::Single(res) => res,
UnionResult::Union(_, _) => unreachable!(),
},
None => *self,
}
}
pub fn symetrical_difference(&self, range: &SimpleRange) -> Option<UnionResult<SimpleRange>>
{
match self.intersection(range)
{
Some(intersecting_part) =>
{
Some((self.without(&intersecting_part)).union(&range.without(&intersecting_part)))
}
None => Some(self.union(range)),
}
}
pub fn min_by_start(&self, range: &SimpleRange) -> SimpleRange
{
if self.start < range.start
{
*self
}
else
{
*range
}
}
pub fn max_by_start(&self, range: &SimpleRange) -> SimpleRange
{
if self.start < range.start
{
*range
}
else
{
*self
}
}
pub fn min_by_end(&self, range: &SimpleRange) -> SimpleRange
{
if self.end < range.end { *self } else { *range }
}
pub fn max_by_end(&self, range: &SimpleRange) -> SimpleRange
{
if self.end < range.end { *range } else { *self }
}
}
impl From<Range<i64>> for SimpleRange
{
fn from(value: Range<i64>) -> Self
{
SimpleRange {
start: LowerBound::Bounded(value.start),
end: HigherBound::Bounded(value.end),
}
}
}
impl From<RangeTo<i64>> for SimpleRange
{
fn from(value: RangeTo<i64>) -> Self
{
SimpleRange {
start: LowerBound::Infinity,
end: HigherBound::Bounded(value.end),
}
}
}
impl From<RangeFrom<i64>> for SimpleRange
{
fn from(value: RangeFrom<i64>) -> Self
{
SimpleRange {
start: LowerBound::Bounded(value.start),
end: HigherBound::Infinity,
}
}
}
impl From<RangeFull> for SimpleRange
{
fn from(_: RangeFull) -> Self
{
SimpleRange {
start: LowerBound::Infinity,
end: HigherBound::Infinity,
}
}
}

16
doz/src/domain/union.rs Normal file
View File

@ -0,0 +1,16 @@
// Module for computing intersection of domains
use crate::domain::Domain;
use crate::domain::DomainRange;
impl DomainRange
{
pub fn union(&self, domain: &DomainRange) -> Domain
{
if let Some(simple_a) = self.is_simple()
&& let Some(simple_b) = self.is_simple()
{
simple_a.union(&simple_b)
}
}
}

1
doz/src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod domain;

16
doz/src/main.rs Normal file
View File

@ -0,0 +1,16 @@
use doz::domain::Domain;
use doz::domain::DomainRange;
fn main()
{
let even = Domain {
ranges: vec![DomainRange {
start: doz::domain::LowerBound::Infinity,
end: doz::domain::HigherBound::Infinity,
modulo: 2,
congruent: 0,
}],
};
println!("{}", even);
}