maths_traits/lib.rs
1//!
2//!# Maths Traits
3//!
4//!A simple to use yet abstract system of mathematical traits for the Rust language
5//!
6//!# Design
7//!
8//!The purpose of this crate is to provide a system for working with mathematical objects
9//!that is both maximally abstract *and* that is easy to use such that working with mathematical
10//!generics and high abstraction is nearly as simple as designing around a specific type.
11//!
12//!This system can be used in cases ranging broadly from something as simple as making [reals](analysis::Real) number
13//!algorithms apply seamlessly to different precisions to simplifying [vector](algebra::VectorSpace)
14//!systems such that using polynomials as coordinates is as easy as switching to a [ring module](algebra::RingModule),
15//!or even something like separating the different poperties of [rings](algebra::ring_like)
16//!from the [Integers](algebra::Integer) so that objects like polynomials can fit into algorithms
17//!generally designed for the latter.
18//!
19//!To accomplish this goal, the provided framework provided is built with a number of design considerations:
20//!* For ease of use and implementation, the included systems utilize [standard Rust][std] or well established
21//! libraries, like [`num_traits`], whenever possible instead of creating new systems.
22//!* Implementors should only have to consider individual properties of structures while users
23//! should only need to use the single trait for whichever mathematical object has the desired features
24//!* The systems have been named and organized to fit mathematical convention as much as possible in
25//! order to add clarity of use while also increasing generality and flexibility
26//!
27//!# Usage
28//!
29//!The traits in this framework are split into two collections, a set of traits for individual properties
30//!and operations and a set of trait aliases for mathematical structures that have those properties.
31//!This way, to support the system, structs need only implement each relevant property, and to use the system,
32//!one can simply bound generics by the single alias of whatever mathematical structure fits their needs.
33//!
34//!For example, to create a generalized `Rational` type,
35//!you would implement the standard [`Clone`](Clone), [`Add`](core::ops::Add), [`Sub`](core::ops::Sub),
36//,
37//, [`Neg`](core::ops::Neg), [`Inv`](num_traits::Inv), [`Zero`](num_traits::Zero),
38// traits, and their assign variants as normal. Then, by implementing the new traits
39//, [`AddAssociative`](algebra::AddAssociative),
40//, [`MulCommutative`](algebra::MulAssociative), and
41//, all of the aliases using those operations (such as [`Ring`](algebra::Ring)
42//!and [`MulMonoid`](algebra::MulMonoid)) will automatically be implemented and usable for the type.
43//!
44//!<details>
45//!<summary> ▶ <i>click to show</i> </summary>
46//!
47//!```
48//!use maths_traits::algebra::*;
49//!
50//!#[derive(Clone)] //necessary to auto-implement Ring and MulMonoid
51//!#[derive(Copy, PartialEq, Eq, Debug)] //for convenience and displaying output
52//!pub struct Rational {
53//! n: i32,
54//! d: i32
55//!}
56//!
57//!impl Rational {
58//! pub fn new(numerator:i32, denominator:i32) -> Self {
59//! let gcd = numerator.gcd(denominator);
60//! Rational{n: numerator/gcd, d: denominator/gcd}
61//! }
62//!}
63//!
64//!//Unary Operations from std::ops and num_traits
65//!
66//!impl Neg for Rational {
67//! type Output = Self;
68//! fn neg(self) -> Self { Rational::new(-self.n, self.d) }
69//!}
70//!
71//!impl Inv for Rational {
72//! type Output = Self;
73//! fn inv(self) -> Self { Rational::new(self.d, self.n) }
74//!}
75//!
76//!//Binary Operations from std::ops
77//!
78//!impl Add for Rational {
79//! type Output = Self;
80//! fn add(self, rhs:Self) -> Self {
81//! Rational::new(self.n*rhs.d + rhs.n*self.d, self.d*rhs.d)
82//! }
83//!}
84//!
85//!impl AddAssign for Rational {
86//! fn add_assign(&mut self, rhs:Self) {*self = *self+rhs;}
87//!}
88//!
89//!impl Sub for Rational {
90//! type Output = Self;
91//! fn sub(self, rhs:Self) -> Self {
92//! Rational::new(self.n*rhs.d - rhs.n*self.d, self.d*rhs.d)
93//! }
94//!}
95//!
96//!impl SubAssign for Rational {
97//! fn sub_assign(&mut self, rhs:Self) {*self = *self-rhs;}
98//!}
99//!
100//!impl Mul for Rational {
101//! type Output = Self;
102//! fn mul(self, rhs:Self) -> Self { Rational::new(self.n*rhs.n, self.d*rhs.d) }
103//!}
104//!
105//!impl MulAssign for Rational {
106//! fn mul_assign(&mut self, rhs:Self) {*self = *self*rhs;}
107//!}
108//!
109//!impl Div for Rational {
110//! type Output = Self;
111//! fn div(self, rhs:Self) -> Self { Rational::new(self.n*rhs.d, self.d*rhs.n) }
112//!}
113//!
114//!impl DivAssign for Rational {
115//! fn div_assign(&mut self, rhs:Self) {*self = *self/rhs;}
116//!}
117//!
118//!//Identities from num_traits
119//!
120//!impl Zero for Rational {
121//! fn zero() -> Self {Rational::new(0,1)}
122//! fn is_zero(&self) -> bool {self.n==0}
123//!}
124//!
125//!impl One for Rational {
126//! fn one() -> Self {Rational::new(1, 1)}
127//! fn is_one(&self) -> bool {self.n==1 && self.d==1}
128//!}
129//!
130//!//algebraic properties from math_traits::algebra
131//!
132//!impl AddAssociative for Rational {}
133//!impl AddCommutative for Rational {}
134//!impl MulAssociative for Rational {}
135//!impl MulCommutative for Rational {}
136//!impl Distributive for Rational {}
137//!
138//!//Now, Ring and MulMonoid are automatically implemented for us
139//!
140//!fn mul_add<R:Ring>(a:R, b:R, c:R) -> R { a*b + c }
141//!use maths_traits::algebra::group_like::repeated_squaring;
142//!
143//!let half = Rational::new(1, 2);
144//!let two_thirds = Rational::new(2, 3);
145//!let sixth = Rational::new(1, 6);
146//!
147//!assert_eq!(mul_add(half, two_thirds, sixth), half);
148//!assert_eq!(repeated_squaring(half, 7u32), Rational::new(1, 128));
149//!```
150//!</details> <p>
151//!
152//!In addition, with little effort, using a more abstract [`Integer`](algebra::Integer)
153//!or [`GCDDomain`](algebra::GCDDomain) bound we can generalize
154//!significantly to be able to have more options for numerators and
155//!denominators, including every primitive integer precision, various big-integer types, or even
156//!structures like polynomials or functions.<p>
157//!
158//!<details>
159//!<summary> ▶ <i>click to show</i> </summary>
160//!
161//!```
162//!use maths_traits::algebra::*;
163//!
164//!//Using a GCDDomain here means we can use more integral types, polynomials, and other types
165//!#[derive(Clone, Copy, PartialEq, Eq, Debug)]
166//!pub struct Rational<T:GCDDomain> {
167//! n:T, d:T
168//!}
169//!
170//!impl<T:GCDDomain> Rational<T> {
171//! pub fn new(numerator:T, denominator:T) -> Self {
172//! let gcd = numerator.clone().gcd(denominator.clone());
173//! Rational{n: numerator.divide(gcd.clone()).unwrap(), d: denominator.divide(gcd).unwrap()}
174//! }
175//!}
176//!
177//!//Standard operations remain basically the same as for the i32 case
178//!
179//!impl<T:GCDDomain> Neg for Rational<T> {
180//! type Output = Self;
181//! fn neg(self) -> Self { Rational::new(-self.n, self.d) }
182//!}
183//!
184//!impl<T:GCDDomain> Inv for Rational<T> {
185//! type Output = Self;
186//! fn inv(self) -> Self { Rational::new(self.d, self.n) }
187//!}
188//!
189//!impl<T:GCDDomain> Add for Rational<T> {
190//! type Output = Self;
191//! fn add(self, rhs:Self) -> Self {
192//! Rational::new(self.n*rhs.d.clone() + rhs.n*self.d.clone(), self.d*rhs.d)
193//! }
194//!}
195//!
196//!impl<T:GCDDomain> AddAssign for Rational<T> {
197//! fn add_assign(&mut self, rhs:Self) {*self = self.clone()+rhs;}
198//!}
199//!
200//!impl<T:GCDDomain> Sub for Rational<T> {
201//! type Output = Self;
202//! fn sub(self, rhs:Self) -> Self {
203//! Rational::new(self.n*rhs.d.clone() - rhs.n*self.d.clone(), self.d*rhs.d)
204//! }
205//!}
206//!
207//!impl<T:GCDDomain> SubAssign for Rational<T> {
208//! fn sub_assign(&mut self, rhs:Self) {*self = self.clone()-rhs;}
209//!}
210//!
211//!impl<T:GCDDomain> Mul for Rational<T> {
212//! type Output = Self;
213//! fn mul(self, rhs:Self) -> Self { Rational::new(self.n*rhs.n, self.d*rhs.d) }
214//!}
215//!
216//!impl<T:GCDDomain> MulAssign for Rational<T> {
217//! fn mul_assign(&mut self, rhs:Self) {*self = self.clone()*rhs;}
218//!}
219//!
220//!impl<T:GCDDomain> Div for Rational<T> {
221//! type Output = Self;
222//! fn div(self, rhs:Self) -> Self { Rational::new(self.n*rhs.d, self.d*rhs.n) }
223//!}
224//!
225//!impl<T:GCDDomain> DivAssign for Rational<T> {
226//! fn div_assign(&mut self, rhs:Self) {*self = self.clone()/rhs;}
227//!}
228//!
229//!impl<T:GCDDomain+PartialEq> Zero for Rational<T> {
230//! fn zero() -> Self {Rational::new(T::zero(),T::one())}
231//! fn is_zero(&self) -> bool {self.n.is_zero()}
232//!}
233//!
234//!impl<T:GCDDomain+PartialEq> One for Rational<T> {
235//! fn one() -> Self {Rational::new(T::one(), T::one())}
236//! fn is_one(&self) -> bool {self.n.is_one() && self.d.is_one()}
237//!}
238//!
239//!impl<T:GCDDomain> AddAssociative for Rational<T> {}
240//!impl<T:GCDDomain> AddCommutative for Rational<T> {}
241//!impl<T:GCDDomain> MulAssociative for Rational<T> {}
242//!impl<T:GCDDomain> MulCommutative for Rational<T> {}
243//!impl<T:GCDDomain> Distributive for Rational<T> {}
244//!
245//!//Now, we can use both 8-bit integers AND 64 bit integers
246//!
247//!let half = Rational::new(1i8, 2i8);
248//!let sixth = Rational::new(1, 6);
249//!let two_thirds = Rational::new(2i64, 3i64);
250//!let one_third = Rational::new(1i64, 3i64);
251//!
252//!assert_eq!(half + sixth, Rational::new(2, 3));
253//!assert_eq!(two_thirds + one_third, Rational::new(1, 1));
254//!```
255//!</details>
256//!
257//!# Currently Supported Constructs
258//!
259//!Currently, `maths_traits` supports traits for the following systems of mathematical structures:
260//! * [Group-Like](algebra::group_like) algebraic structures: monoids, groups, abelian groups, etc
261//! * [Ring-Like](algebra::ring_like) algebraic structures: rings, fields, GCD domains, Euclidean domains, etc
262//! * [Module-Like](algebra::module_like) structures: vector spaces, algebras, bilinear-forms, etc
263//! * [Integer](algebra::integer::Integer) and [Natural](algebra::integer::Natural) numbers
264//! * [Ordered](analysis::ordered) algebraic structures: ordered/archimedian rings, fields, etc
265//! * [Real](analysis::real::Real) and [Complex](analysis::real::Complex) numbers
266//! * [Metric](analysis::metric) properties of sets: metric spaces, inner-product, norm, etc
267//!
268//!# `no_std`
269//!
270//!It is possible to use `maths-traits` without the standard library. To do so, simply compile your project
271//!without the `std` feature by disabling default features in your `Cargo.toml`.
272//!
273//!```TOML
274//![dependencies]
275//!maths-traits = {version = "0.2", default-features = false}
276//!```
277//!
278//!However, do note that the implementations of all traits related to [`Real`](analysis::Real) on
279//!primitive types will only be available when using `std`, as the floating-point trigonometric
280//!and exponential functions are only available when linking to the standard library.
281//!
282//!# Possible Future Features
283//!
284//!As `maths_traits` is still in developement, there are a number of features that may be included
285//!at a later date:
286//! * Traits for vector spaces of finite or countable dimension that have discrete elements. This
287//! will *almost certainly* be added eventually, but hasn't yet due to a number of design
288//! constraints.
289//! * Optional default implementations for the other mathematical strutures in the `num` crate.
290//! * A system for category-like structures, ie, sets with an operation that is partial over its elements.
291//! This would relatively simple to add, but *so far*, there do not seem to be enough use cases for such a
292//! system in order to offset the added code complexity.
293//! * Systems for sets, geometric shapes, and set measure. The might be included in the future, but
294//! so far, they do not seem to fit within the scope of this project.
295//!
296//!Of course, if anyone feels that any specific feature be added, feel free to file an issue or
297//!contribute at the [github](https://github.com/anvil777/maths-traits) repository. Since most
298//!of the non-implemeted features are non-implemented due to usefulness concerns, if a feature is
299//!requested (and is reasonable), it will probably be added at some point afterward
300//!(though this is not a guarantee).
301//!
302//!# Release Stability
303//!
304//!At the moment, this project is still in developement, so do note that it is entirely possible
305//!for the API to change in the future. I simply do not feel that the crate has had enough use to
306//!warrent a feature freeze of any kind, so I would like to leave that within the realm of possibility.
307//!
308//!_However_, as it stands currently, a fair portion of subsystems have more-or-less been stable in my own
309//!personal use for some time, and I would specifically expect most changes to
310//!occur in the module-like, metric, and integer systems, so there should not be a terribly large
311//!number of breaking changes in the future.
312//!
313//!Of course, if an API-breaking change _is_ introduced at any point it will be reflected in
314//!the semantic-versioning.
315//!
316
317#![feature(trait_alias)]
318#![feature(specialization)]
319#![feature(extra_log_consts)]
320
321#![cfg_attr(not(feature = "std"), no_std)]
322
323pub mod algebra;
324pub mod analysis;