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

#![feature(trait_alias)]
#![feature(specialization)]
#![feature(extra_log_consts)]

#![cfg_attr(not(feature = "std"), no_std)]

pub mod algebra;
pub mod analysis;