dimforge / alga Goto Github PK
View Code? Open in Web Editor NEWAbstract algebra for Rust.
Abstract algebra for Rust.
The 128bit integers traits do not seem to be implemented.
I find myself with a structure for which Eq
is appropriate and RelativeEq
is not. Approx or exact comparison should probably be caller selectable.
If I understand correctly every RealField
must implement ComplexField
(with the imaginary part set to zero) and every ComplexField
must be a super-set of f64
, that is, it must be able to represent all values of f64 logically (disregarding machine specific limitations). Decorum's N64
and R64
types logically cannot be NotANumber or Infinity. They thus are not logical super-sets of f64
.
For my calculations results of NaN or Infinity are logical errors. I put finite numbers in and expect my calculations to result in finite numbers. I'd thus like to use Deorum's numbers.
My attempt to implement the traits, required for ComplexField, failed at the above requirement. Would it be possible to remove the requirement or replace it by a softer requirement, like Decorum's Real
or Real+Encoding
?
Given:
fn add<T: Real, U: Real>(x: T, y: U) -> ??? {
x + y
}
I'd like to fill the ???
with either T
or U
, depending which one is wider. What's the alga way of unifying Real
s in computations?
The lattice trait hierarchy could be extended with a bounded meet semilattice, bounded join semilattice, then a bounded lattice. This would be useful to lawfully express set operations as well as binary operations.
It seems that the infrastructure for parts of this is already in place with the Identity trait.
For a possible trait hierarchy, see https://github.com/typelevel/algebra/blob/master/core/src/main/scala/algebra/lattice/BoundedLattice.scala
Adding prelude so that usual usage of alga would look like this would be useful:
extern crate alga;
use alga::prelude::*
I found that writing generic arithmetic with alga involves some extra clones. The reason is, that there is no way to apply operators to references. Therefore you have to pass ownership to the operator, which requires a clone, as soon as you need a value more than once.
For example, given two (large) vectors, a: T
and b: U
, where T: ClosedAdd<U>
, I would like to be able to do all of these operations:
// possible today
a + b
a += b
// not possible without adding extra trait bounds
a + &b
&a + b
&a + &b
a += &b
That would probably require the ClosedAdd
trait to be extended to this
trait ClosedAdd<Right = Self>:
Sized +
Add<Right, Output = Self> +
for<'a> Add<&'a Right, Output = Self> +
AddAssign<Right> +
for<'a> AddAssign<&'a Right>
where
for<'a> &'a Self: Add<Right, Output = Self>,
for<'a, 'b> &'a Self: Add<&'b Right, Output = Self>
{}
Of course, this adds extra burden on trait implementors. It is also a backwards-incompatible change, as it breaks implementations that do not fulfill the extra bounds yet. (afaik, at least nalgebra should be fine.)
I would argue, that any arithmetic type should be able to handle these cases. Happy to hear a counter-example, but I can't really think of any yet.
The FiniteDimVectorField
should be implemented for the f32
and f64
type.
A motivating example is the representation of an Initial Value Problem.
extern crate alga;
use alga::general::RealField;
use alga::linear::FiniteDimVectorSpace;
pub struct IVPProblem<'a, T, S>
where
T : RealField,
S : FiniteDimVectorSpace<Field = T>
{
initial_state : S,
tspan: (T,T),
func : &'a dyn Fn(&T, &S) -> S,
}
If we would now want to implement the exponential equation given by dy/dt=dy
you could try to implement it as
fn main() {
let ivp_problem = IVPProblem {
initial_state : 1.0,
tspan : (0.0, 1.0),
func : &(|_, &y| y)
};
/// More code here
}
This would not compile because our initial_state is an f64
-type and the trait FiniteDimVectorSpace<Field = f64>
is not implemented.
I'm very much not a mathematician, nor am I a Rust expert, so please forgive me if this is a silly question.
I'm working on a spline implementation which I will mostly use for 3D curves, but I would also like it to work for 2D curves and for 1D (I don't know if those can still be called "curves").
For 2D and 3D I'm using vector types from the nalgebra
crate (which implement several alga
traits).
Since my implementation is supposed to work on any vector space that has a norm, I think it would make sense to use the alga::linear::NormedSpace
trait bound.
For the 1D case I could of course use a 1D vector from nalgebra
, but I think it would be much nicer if I could also use a "normal" scalar type, like e.g. f64
.
This doesn't work though, because NormedSpace
doesn't seem to be implemented for f64
(it looks like it's only implemented for Complex<N>
).
Now my question: are real numbers a normed space?
I would think so, but what do I know ...
If that makes at least some mathematical sense, would it be possible to implement NormedSpace
for scalars?
I'm thinking about something like this:
impl<T: RealField> NormedSpace for T {
type RealField = T;
...
fn norm(&self) -> T {
self.abs()
}
...
}
Or probably this should use ComplexField
instead?
Here is example code of the macros:
https://play.rust-lang.org/?gist=584830a89044aca1a59be9e310b02fb5&version=stable&backtrace=0
It doesn't include implementing identity or inverse yet. Also making it to create quickcheck test cases would be good.
Fedora maintainer here!
I would appreciate if you would update quickcheck dependency to 0.8 so that won't have to ship multiple versions of quickcheck ;)
I suspect this is more of a usage error than a bug, but can't anywhere else to go for help.
I'm trying to use the ncollision2d and decimal crates, and keep getting this error:
error[E0277]: the trait bound `decimal::d128: alga::general::Real` is not satisfied
--> src/misc.rs:86:3
|
86 | pub cuboid: Cuboid<d128>,
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `alga::general::Real` is not implemented for `decimal::d128`
|
= note: required by `ncollide2d::shape::Cuboid`
Among others, I have this in my Cargo.toml:
[dependencies]
ncollide2d = "0.17.1"
decimal = "2.0.4"
[dependencies.alga]
version = "0.7.1"
features = ["decimal"]
As far as I can tell, that should enable the Real trait for decimal, but it isn't working. Is this a problem with alga? If not, can you tell me what I'm missing?
Thanks.
There is a Real
trait but not a ready-to-use Integer
trait.
Now I'm using the RingCommutative
trait to define the classical integer number set, but there is no motivation for not introduce an alias trait Integer
.
Am I missing something?
Is there a standard implementation for the trivial group, as part of this crate, or somewhere else?
Currently alga
uses quickcheck for it's own tests.
It should provide straight forward way for it's users to make use of it too.
One avenue worth exploring would be to include quickcheck test with the convenience macros that I added.
(This wish came about implementing geometric algebra library: https://github.com/WaDelma/galgebra. It's quite WIP and propably wrong as I am just now trying to figure this whole thing out :D)
This would be a breaking change, because presumably DirectIsometry
implementors would also be required to implement DirectSimilarity<Scaling=Id>
. However, this would be very useful for things like the transformations on an entity in a graphical scene, where zero or negative scales can cause ugly problems.
Hiya, currently alga-derive
on crates.io still uses syn 0.15
, but in the repository it already is bumped to syn 1.0
. Please may we have a release of alga-derive 0.9.2
to receive the update? Thank you!
Currently top level documentation of the crate doesn't contain (pretty much) anything. Add explanation what the crate is and how to use it to it.
See dimforge/nalgebra#206 and the decimal crate.
alga
implements the Lattice
trait for primitive f32
and f64
types while providing infallible pair-wise meet
and join
operations. This seems to interact poorly with NaN
s, which do not compare with other floating point values regardless of what they encode (the result is always false
with the sole exception of !=
).
Given this comparison and some floating point value x
, (NaN โจ x)
produces x
while (x โจ NaN)
produces NaN
, because NaN >= x
and x >= NaN
are never true. Considering that NaN
has no ordering w.r.t. any elements in the set of floating point values, can there be a greatest lower bound or least upper bound?
If the intention is to simply propagate NaN
s as a sort of special case (rather than using a fallible API via Option
or Result
), then perhaps the implementation should produce NaN
if either operand is NaN
. "Garbage in, garbage out" probably applies here as well. :-) Do you have any thoughts on this?
I'm seeking help in implementing the Scalar trait for dual numbers, specifically for the dual_num crate (which is currently undergoing an upgrade to support automatic partial derivatives). Please correct me if I'm wrong, but I think that mathematically, a dual number is indeed scalar (in the case of dual_num it is represented as a na::Vector2
but that should not alter its mathematical properties).
The purpose for implementing Scalar
for dual number is to greatly simplify mathematical operations when using dual numbers in conjunction with the nalgebra
crate.
Thanks for the support
P.S.: I think that these dual numbers could be represented in a similar fashion to how Vec2<Scalar>
is represented in this example. I'll try that out.
cgmath currently has a MetricSpace
trait that is defined for vectors, points, and quaternions:
pub trait MetricSpace: Sized {
type Metric: BaseFloat;
fn distance2(self, other: Self) -> Self::Metric;
fn distance(self, other: Self) -> Self::Metric { ... }
}
Could we consider rejiggering the alga::linear
trait hierarchy to add something like this?
Extra parens at alga/alga/src/linear/transformation.rs:371:14 keep the library from compiling. Some((b.norm() / a.norm()))
-> Some(b.norm() / a.norm())
fixes it.
cargo build Compiling alga v0.5.2 (file:///Users/wbeard/repos/proto/hello_alg/alga/alga) warning: unused macro definition --> alga/alga/src/macros.rs:143:1 | 143 | / macro_rules! impl_approx_eq { 144 | | ($V:expr; $($T:ty),* $(,)*) => { 145 | | $(impl ApproxEq for $T { 146 | | type Eps = $T; ... | 158 | | } 159 | | } | |_^ | = note: #[warn(unused_macros)] on by defaultwarning: unused macro definition
--> alga/alga/src/general/one_operator.rs:84:1
|
84 | / macro_rules! impl_quasigroup(
85 | | (<$M:ty> for $($T:tt)+) => {
86 | | impl_marker!($crate::general::AbstractQuasigroup<$M>; $($T)+);
87 | | }
88 | | );
| |__^warning: unused macro definition
--> alga/alga/src/general/one_operator.rs:184:1
|
184 | / macro_rules! impl_loop(
185 | | (<$M:ty> for $($T:tt)+) => {
186 | | impl_quasigroup!(<$M> for $($T)+);
187 | | impl_marker!($crate::general::AbstractLoop<$M>; $($T)+);
188 | | }
189 | | );
| |__^error: unnecessary parentheses around function argument
--> alga/alga/src/linear/transformation.rs:371:14
|
371 | Some((b.norm() / a.norm()))
| ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses
|
note: lint level defined here
--> alga/alga/src/lib.rs:18:9
|
18 | #![deny(unused_parens)]
| ^^^^^^^^^^^^^error: aborting due to previous error
error: Could not compile
alga
.To learn more, run the command again with --verbose.
Hello!
I would like to construct a polynomial ring over a finite field, but I am new to Rust and this type of math.
Can this library be used for this and, if so, can someone point me in the right direction?
Thanks!
If I define an additive group according to the instructions in the documentation, it still will not satisfy the AdditiveGroup trait, and I can't do addition with it (e.g. element + element
).
use alga::general::{AbstractMagma, Additive, AdditiveGroup, Identity, Inverse}; // 0.7.2
use alga_derive::Alga; // 0.7.1
#[derive(Alga, Clone, Copy, PartialEq, Debug)]
#[alga_traits(Group(Additive))]
pub struct TrivialGroup;
impl AbstractMagma<Additive> for TrivialGroup {
fn operate(&self, _right: &Self) -> Self {
TrivialGroup {}
}
}
impl Identity<Additive> for TrivialGroup {
fn identity() -> Self {
TrivialGroup {}
}
}
impl Inverse<Additive> for TrivialGroup {
fn inverse(&self) -> Self {
TrivialGroup {}
}
}
struct Bar<T: AdditiveGroup> {
t: T,
}
fn main() {
let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
}
Gives the error:
error[E0277]: the trait bound `TrivialGroup: num_traits::identities::Zero` is not satisfied
--> src/main.rs:31:15
|
31 | let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
| ^^^^^^^^^^^^^^^^^^^ the trait `num_traits::identities::Zero` is not implemented for `TrivialGroup`
|
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
--> src/main.rs:26:1
|
26 | struct Bar<T: AdditiveGroup> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `TrivialGroup: std::ops::Neg` is not satisfied
--> src/main.rs:31:15
|
31 | let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
| ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Neg` is not implemented for `TrivialGroup`
|
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedNeg` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
--> src/main.rs:26:1
|
26 | struct Bar<T: AdditiveGroup> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: cannot subtract `TrivialGroup` from `TrivialGroup`
--> src/main.rs:31:15
|
31 | let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
| ^^^^^^^^^^^^^^^^^^^ no implementation for `TrivialGroup - TrivialGroup`
|
= help: the trait `std::ops::Sub` is not implemented for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedSub` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveQuasigroup` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
--> src/main.rs:26:1
|
26 | struct Bar<T: AdditiveGroup> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: cannot subtract-assign `TrivialGroup` from `TrivialGroup`
--> src/main.rs:31:15
|
31 | let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
| ^^^^^^^^^^^^^^^^^^^ no implementation for `TrivialGroup -= TrivialGroup`
|
= help: the trait `std::ops::SubAssign` is not implemented for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedSub` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveQuasigroup` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
--> src/main.rs:26:1
|
26 | struct Bar<T: AdditiveGroup> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: cannot add-assign `TrivialGroup` to `TrivialGroup`
--> src/main.rs:31:15
|
31 | let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
| ^^^^^^^^^^^^^^^^^^^ no implementation for `TrivialGroup += TrivialGroup`
|
= help: the trait `std::ops::AddAssign` is not implemented for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedAdd` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveSemigroup` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveMonoid` for `TrivialGroup`
= note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
--> src/main.rs:26:1
|
26 | struct Bar<T: AdditiveGroup> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
See also: https://stackoverflow.com/questions/54303935/defining-additivegroup-with-alga-crate
Recall this definition:
pub trait FiniteDimVectorSpace: VectorSpace + Index<usize, Output = Self::Field> + IndexMut<usize, Output = Self::Field> {
fn dimension() -> usize;
fn canonical_basis_element(i: usize) -> Self;
fn dot(&self, other: &Self) -> Self::Field;
unsafe fn component_unchecked(&self, i: usize) -> &Self::Field;
unsafe fn component_unchecked_mut(&mut self, i: usize) -> &mut Self::Field;
fn canonical_basis<F: FnMut(&Self) -> bool>(f: F) { ... }
}
Note that FiniteDimVectorSpace::dimension
is independent of &self
. This forces all implementors of this trait to return constant value. Therefore, Vec<T>
where T: Field
is not a vector over the field T
.
This is an awkward definition. It might make some sense for vector space of a certain dimension known at compile time, such as Vec2
and Vec3
in the examples. However, it prohibits implementations in general.
The dimension
associated method in the definition of SquareMatrix
makes much less sense in this context. Recall its definition:
pub trait SquareMatrix: Matrix<Row = Self::Vector, Column = Self::Vector, Transpose = Self> + MultiplicativeMonoid {
type Vector: FiniteDimVectorSpace<Field = Self::Field>;
fn diagonal(&self) -> Self::Vector;
fn determinant(&self) -> Self::Field;
fn try_inverse(&self) -> Option<Self>;
fn dimension(&self) -> usize { ... }
fn transpose_mut(&mut self) { ... }
}
The dimension
associated method in this case takes &self
, but it is in fact independent of &self
once Self::Vector
has constant rank at compile time.
The proposed change is to allow FiniteDimVectorSpace::dimension
to accept &self
.
See https://discourse.nphysics.org/t/starting-an-umbrella-organisation-on-github/246/3.
Link to the organization under construction.
I intend to migrate the alga, nalgebra, ncollide, and nphysics crates to rustsim.
Please let me know if you which to be added as a member of the organization: https://github.com/rustsim.
As there now is custom derive based solution macro_rules
based one isn't nessary.
Only thing that macro_rules
based one allows that custom derive doesn't is to implement the trait for types not in current crate. Because how orphan rules work this is only relevant to alga
itself.
So I propose removing #[macro_export]
from all of the macros.
Currently generic parameter requirement affect the algebraic trait and all it's super traits.
Most simple way of fixing this would be to allow different where clauses for subtraits, but this would be cumbersome.
Currently alga_derive
doesn't have specific readme for it and the description in crates.io shows the same contents as alga
.
I think it would be beneficial to have traits for functions (exp, sin, pow, ...) that are separate from numbers (partialOrd, Signed, ...). For example, when one wants to use complex numbers (since ComplexNumbers are now implementing a lot of the alga traits now) it is not uniquely defined how to order them. Nevertheless it would be great to be able to have the exp, log, ... functions in a trait without requiring them to be ordered in any way. It would be an equivalent of the Num, NumOps trait of the num_trait crate.
What do you think?
Hello,
alga_derive is the only one in Fedora which pulls syn 0.11, the rest is using 0.15. I would appreciate if you would update dependency.
Thanks!
Currently there isn't readme on the top level of the repo. Move the alga
readme to top level or create new one.
This documentation https://docs.rs/alga/0.5.3/alga/general/index.html#identity-elements mentions IdentityAdditive and IdentityMultiplicative traits which apparently do not exist.
Maybe it should refer to num_traits::identities instead?
When macros 1.1 are stable (rust-lang/rfcs#1681) macros implementing traits should propably turned into attributes.
Currently the Inverse
trait has a .inverse
method that returns the inverse of an element with respect to a given operator (additive or multiplicative). We should rename this to avoid conflicts on types from other crates that have an inverse
method and also implement Inverse
from alga.
In particular, this can lead to very confusing scenarios where users call .inverse
on Matrix4
from nalgebra and end up with the additive inverse where they actually needed try_inverse()
to obtain the multiplicative inverse.
Renaming Inverse
to TwoSidedInverse
and .inverse
to .two_sided_inverse
will reduce the ambiguity and will make the name of this trait more precise anyway.
There is currently two problems with this:
AbstractModule
contains multiply_by
making it non-marker trait.
VectorSpace
(the fact that this isn't called AbstractVectorSpace
needs to be hardcoded) and AbstractModule
have associated type that needs to be specified somehow.It would be nice to make the obsoleted rustc-serialize optional by adding it as a default feature that could be turned off. I'm having a hard time compiling to a specific target and it looks like rustc-serialize is the culprit.
Not sure if there's anything in alga that specifically relies on it though.
I am trying to implement the ring of integers mod n for n non-prime (so this is a ring, not a field). Here is a link to the relevant code.
The section which errors has the following form:
#[derive(Clone, Copy, PartialEq, Alga)]
#[alga_traits(Ring(Additive, Multiplicative))]
struct Modular<const Q: u32>(u32);
The rest of the code is implementing various traits.
The particular error is below:
error[E0277]: the trait bound `Modular<Q>: TwoSidedInverse<Multiplicative>` is not satisfied
--> src/lib.rs:10:34
|
10 | #[derive(Clone, Copy, PartialEq, Alga)]
| ^^^^ the trait `TwoSidedInverse<Multiplicative>` is not implemented for `Modular<Q>`
|
::: /home/mark/.cargo/registry/src/github.com-1ecc6299db9ec823/alga-0.9.3/src/general/one_operator.rs:49:36
|
49 | PartialEq + AbstractMagma<O> + TwoSidedInverse<O>
| ------------------ required by this bound in `AbstractQuasigroup`
|
= help: the following implementations were found:
<Modular<Q> as TwoSidedInverse<Additive>>
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `Modular<Q>: TwoSidedInverse<Multiplicative>` is not satisfied
--> src/lib.rs:10:34
|
10 | #[derive(Clone, Copy, PartialEq, Alga)]
| ^^^^ the trait `TwoSidedInverse<Multiplicative>` is not implemented for `Modular<Q>`
|
::: /home/mark/.cargo/registry/src/github.com-1ecc6299db9ec823/alga-0.9.3/src/general/one_operator.rs:189:38
|
189 | pub trait AbstractLoop<O: Operator>: AbstractQuasigroup<O> + Identity<O> {}
| --------------------- required by this bound in `AbstractLoop`
|
= help: the following implementations were found:
<Modular<Q> as TwoSidedInverse<Additive>>
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
error: could not compile `latticecrypto`
To learn more, run the command again with --verbose.
It seems that the issue is that I have not provided a TwoSidedInverse implementation. But I want to implement an integral domain for which not every element has a multiplicative inverse, so this seems like the "right" thing to be doing.
Is this behavior expected? Is there some other way that I can use alga
to implement the modular arithmetic mod n for n composite?
Hi there.
I could not find any place to ask for this. Please excuse me for the question. How can I get MIN or MAX of a Real?
For context, this idea is motivated by vbarielle/sprs#118.
The matrix trait is rather large at the moment:
pub trait Matrix: Sized + Clone + Mul<Self::Row, Output = Self::Column> {
type Field: Field;
type Row: FiniteDimVectorSpace<Field = Self::Field>;
type Column: FiniteDimVectorSpace<Field = Self::Field>;
type Transpose: Matrix<Field = Self::Field, Row = Self::Column, Column = Self::Row>;
fn nrows(&self) -> usize;
fn ncolumns(&self) -> usize;
fn row(&self, i: usize) -> Self::Row;
fn column(&self, i: usize) -> Self::Column;
unsafe fn get_unchecked(&self, i: usize, j: usize) -> Self::Field;
fn transpose(&self) -> Self::Transpose;
fn get(&self, i: usize, j: usize) -> Self::Field { ... }
}
For many algorithms, access to the internal structure of the matrix is not necessary. It also does put some burden on trait implementors that may be possible to avoid.
A suggested solution would be to introduce a more abstract linear operator inspired by SciPy's interface with the same name as a supertrait.
pub trait LinearOperator: Sized + Clone + Mul<Self::Row, Output = Self::Column> {
type Field: Field;
type Row: FiniteDimVectorSpace<Field = Self::Field>;
type Column: FiniteDimVectorSpace<Field = Self::Field>;
type Transpose: LinearOperator<Field = Self::Field, Row = Self::Column, Column = Self::Row>;
fn nrows(&self) -> usize;
fn ncolumns(&self) -> usize;
fn transpose(&self) -> Self::Transpose;
}
pub trait Matrix: LinearOperator {
fn row(&self, i: usize) -> Self::Row;
fn column(&self, i: usize) -> Self::Column;
unsafe fn get_unchecked(&self, i: usize, j: usize) -> Self::Field;
fn get(&self, i: usize, j: usize) -> Self::Field { ... }
}
It would be useful to include matrix multiplication there as well, but I have a feeling that this is hard to express in today's Rust. It also seems like a separate issue as the original matrix trait does not include this either.
Thank you all so much for adding in complex support! It makes my project 100x easier now that I can use existing matrix functions with complex numbers. I have just a few lingering concerns about the traits.
First of all, would it be possible to remove the Bounded
requirement of RealField
? Although this would be a breaking change, it would allow using arbitrary-size numbers or rationals, as long as they implement Copy
. I understand the argument that they should probably implement Clone
instead, but on the other hand, I seriously doubt that many functions rely on Bounded
, and that could be added as a generic requirement for those limited cases. Furthermore, using Bounded
does not really make much sense for floating point numbers anyway since it is almost always impractical that any number should ever come even close to the maximum possible float (since they store an exponent and significand rather than a binary number like u8
; f64::MAX
> 10308).
Second, is the 'static
requirement for ComplexField
really necessary? Yes, I know that removing this would be very breaking, and make things a bit more difficult to write, but I IMHO at least eventually it is a necessary step in order to write any performant code using alga
in order to avoid memory leaks. Same goes for Send
, Sync
, Any
, and Debug
/Display
. As is the case for Bounded
, I think it would make more sense for rarely-used requirements like these to be specified for individual functions and to only require the real necessities like arithmetic as a requirement for all ComplexField
and thereby RealField
numbers.
Third, one more breaking change: would it be possible to eventually refactor the requirements for trigonometric/hyperbolic/exponential/logarithmic, etc. functions into requirements for the corresponding traits in num_traits
? This would make implementing those functions easier. Or better yet, at least for RealField
, would it be possible to remove those requirements except for the functions that use them?
Overall, the most important request I have is removing 'static
. Everything else is just a suggestion/proposal, but IMHO removing 'static
is essential for proper memory management even if it makes generics a bit more difficult.
Thank you again, and please note that everything here is just ideas for consideration and not feature requests. I understand if not everything here would make sense to implement.
This code example fails:
fn foo<V: VectorSpace<Field=f64>>(a: V, b: V, c: f64) -> V {
a * c + c * b
}
with this error:
error[E0277]: the trait bound `f64: std::ops::Mul<V>` is not satisfied
|
| a * c + c * b
| ^ no implementation for `f64 * V`
|
= help: the trait `std::ops::Mul<V>` is not implemented for `f64`
= help: consider adding a `where f64: std::ops::Mul<V>` bound
(omitted source location in my project for clarity)
Is there a reason, why this can't be made work? As multiplication on the field commutes anyway, the operator should generally be available in this way.
The implementation of angle
function on trait InnerSpace
is incorrect. When calculating cang
, instead of multiplying the inner product by the norms of two vectors, it should be dividing them.
The correct calculation should be let cang = prod.real().unscale(n1 * n2);
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.