Operator overloading involving complex and float values - rust

Update: This bug has been fixed by https://github.com/rust-lang/rust/pull/23673 . The code below now works.
In math and numerical programming, it is expected that complex numbers interoperate seamlessly with real (floating point) values. Is it possible in Rust to define a struct Complex<T: Float> that allows symmetric math operations involving values of type T?
For example, one can define the operator * for inputs (Complex<T>, Complex<T>) and (Complex<T>, T) as follows:
use std::ops::Mul;
use std::num::Float;
#[derive(Copy, Debug)]
pub struct Complex<T: Float> {
pub re: T, pub im: T
}
impl<T: Float> Complex<T> {
pub fn new(re: T, im: T) -> Complex<T> {
Complex { re: re, im: im }
}
}
impl<T: Float> Mul<Complex<T>> for Complex<T> {
type Output = Complex<T>;
fn mul(self, other: Complex<T>) -> Complex<T> {
Complex::new(self.re * other.re - self.im * other.im,
self.re * other.im + self.im * other.re)
}
}
impl<T: Float> Mul<T> for Complex<T> {
type Output = Complex<T>;
fn mul(self, other: T) -> Complex<T> {
Complex::new(self.re * other, self.im * other)
}
}
Is it possible to overload * to also work on the inputs (T, Complex<T>)? For example, the following doesn't work:
impl Mul<Complex<f64>> for f64 {
type Output = Complex<f64>;
fn mul(self, other: Complex<f64>) -> Complex<f64> {
Complex::new(self * other.re, self * other.im)
}
}
fn main() {
let x = Complex::new(1.0, 1.0);
let y = x*x;
let z = x*4.0;
let w = 4.0*x;
}
I get the error message:
error: mismatched types:
expected `_`,
found `Complex<_>`
(expected floating-point variable,
found struct `Complex`) [E0308]
src/main.rs:61 let w = 4.0*x;
^
In Scala, one might work around this problem with an implicit conversion from T to Complex<T>. Are there similar tricks in Rust? Is there a better way to define an efficient, generalized * operation? Thanks.

This should be allowed, but there's an outstanding issue that prevents built-in types (u8, f32, etc) from being used on the left-hand side of the operation when a custom implementation is in play.
The suggested workaround for now is to put the custom type on the left-hand side and the built-in type on the right.

Related

Rust Matrix Type with Specialized and Generic Functions

Given a matrix type in Rust using const generic parameters, something like this:
pub struct Mat<T, const R: usize, const C: usize>
{
m: [[T; C]; R],
}
I am aware that specializations are not available (yet, and not for this type of
specialization it seems?), but it seems like it is possible to implement some
'specializations' for specific instances of this type, e.g.:
impl<T> Mat<T, 2, 2>
{
pub fn invert(self) -> Self
where T: From<f32> + Clone + std::ops::Neg<Output=T> + std::ops::Sub<T, Output = T> +
std::ops::Mul<T, Output = T> + std::ops::Div<T, Output = T>
{
let r = T::from(1.0) / self.clone().determinant();
Mat::new([[ self[1][1]*r.clone(), -self[0][1]*r.clone()],
[-self[1][0]*r.clone(), self[0][0]*r]])
}
pub fn determinant(self) -> T
where T: std::ops::Sub<T, Output = T> + std::ops::Mul<T, Output = T>
{
self[0][0]*self[1][1] - self[0][1]*self[1][0]
}
}
Similar 'specializations' can be implemented for 3x3 and 4x4 matrices.
However, at some point I would like to also implement a generalized
determinant/inverse, something like this:
impl<T, const N: usize> Mat<T, N, N>
{
/// Generalized matrix inversion.
pub fn gen_invert(self) -> Self
{
// TODO: determinant(), matrix_minor(), cofactor(), adjugate()
Mat::default()
}
/// Generalized matrix determinant.
pub fn gen_det(self) -> T
{
match N
{
1 => self.determinant(), // <- Wrong type Mat<T, N, N>, not Mat<T, 1, 1>.
// 2 => // Same as above.
_ => general_fn(),
}
}
}
This turned out to be hard however, since there does not seem to be any way to
cast or even transmute a type of Mat<T, N, N> to Mat<T, 1, 1>, even though we
know that the sizes are correct, given that is done on a const variable under
an appropriate match case. Is there some way to accomplish the above without an
expensive from() function that manually creates a Mat<T, 1, 1> from the Mat<T,
N, N>?
Additionally, is there some way to avoid renaming the generalized versions of
these functions? I tried to do that using traits, similar to this question, but
since all functions have the same name this does not appear to work for this
case.
(There are even more complications with this though, since computing minor
matrices requires arithmetic on const generics and that is only in nightly Rust
right now, but that is beyond the scope of this question.)

In Rust, is it possible to return a static function from a function?

Suppose I have the following type in Rust:
type UnOp = fn(u64) -> u64;
That type allows me to create different unary operations:
const add1 : UnOp = |x| x + 1;
const mul2 : UnOp = |x| x * 2;
Now, suppose that I needed add2, add3, add4 (...), for different numbers, in different places of my code. Writing all definitions would be cumbersome, so, instead, I write a generic adder function:
fn adder(add : u64) -> UnOp {
|x| x + add
}
This would allow me to write add(2), add(3), etc., for any number:
// Prints 2 + 40
println!("result is: {}", adder(2)(40))
The problem is: adder is actually not valid Rust code, since |x| ... is a closure, not a static function. In order for adder to work as I want, I need to modify UnOp to be a closure instead:
type UnOp = Box<dyn Fn(u64) -> u64>;
fn adder(add : u64) -> UnOp {
Box::new(move |x| x + add)
}
The problem is: what if I know every usage of adder(N) is applied to a static value?
In that case, creating dynamic closures would be wasteful, computation-wise. Not only that, Box<dyn ...> greatly complicates the code, and may even need lifetime annotations. My question is:
Is it possible to create adder, without modifying the original definition of UnOp? That is, letting UnOp be a static function, NOT a closure?
Logically, there is no reason it shouldn't be possible, as long as the arguments of adder are static, Rust should be able to just expand it at compile time, to generate each particular instance.
Edit: additional details
A great solution, proposed by #Netwave's answer, is to use Generic consts, which solves this problem for the specific example I gave. Sadly, it doesn't work in case UnOp is polymorphic, or if the constant argument is itself a function:
type UnOp<A> = fn(A) -> A;
pub fn adder<const ADD: u64>() -> UnOp<u64> {
|x| ADD + x
}
pub fn apply<A, const op : UnOp<A>, const x : A>() -> A {
return op(x);
}
This raises 2 errors:
- the type of const parameters must not depend on other generic parameters
- using function pointers as const generic parameters is forbidden
You can do it using const Generics:
type UnOp = fn(u64) -> u64;
const fn adder<const ADD: u64>(x: u64) -> u64 {
ADD + x
}
fn main() {
let add_1: UnOp = adder::<1>;
println!("{}", add_1(1));
}
Playground
Is it possible to create adder, without modifying the original definition of UnOp? That is, letting UnOp be a static function, NOT a closure?
Since you don't explain why I will ignore this requirement. As I think you limit you option for nothing.
You could prefer a clever use of generic and trait:
trait UnOp {
fn call(&self, _: u64) -> u64;
}
impl<F> UnOp for F
where
F: Fn(u64) -> u64,
{
fn call(&self, x: u64) -> u64 {
self(x)
}
}
fn adder(add: u64) -> impl UnOp {
move |x| x + add
}

What is going on with `unconstrained generic constants` in Rust?

I was experimenting with const generics when this strange error came out: error: unconstrained generic constant. What does it mean?
Maybe I should describe what was I tried to do before actual code - I wanted to treat types as numbers, using Lisp-like Cons and Nil.
Here's an example:
use core::marker::PhantomData;
struct Nil;
struct Cons <N> (PhantomData <N>);
So '1' is Cons <Nil>, '2' - Cons <Cons <Nil>>, etc.
Then I tried to implement extracting normal number from this.
trait Len {
const N: usize;
}
impl <N: Len> Len for Cons <N> {
const N: usize = 1 + N::N;
}
impl Len for Nil {
const N: usize = 0;
}
And it works.
Then I started doing actual job: my true task was not to just experiment with generic types, but to implement mathematical vecs, just like(maybe you know) in shaders.
So I tried to implement such powerful constructor:
vec3 i = vec3(1.0, 1.0, 1);
vec4 v = vec4(i);
I have decided to treat any value as 'Piece' and then just compound pieces together.
trait Piece <T> {
type Size: Len;
fn construct(self) -> [T; Self::Size::N];
}
No problems so far. Next step is to define few auxiliary traits(since rust does not yet support negative bounds):
pub auto trait NotTuple {}
impl <T> !NotTuple for (T,) {}
pub auto trait NotList {}
impl <T, const N: usize> !NotList for [T; N] {}
I am using nightly rust, so few #![feature]-s is not a problem.
Then, we can use it:
type One = Cons <Nil>;
impl <T: Copy + From <U>, U: Copy + NotTuple + NotList> Piece <T> for U {
type Size = One;
fn construct(self) -> [T; Self::Size::N] {
[T::from(self)]
}
}
This one constructs piece from an argument.
Everything is still good.
impl <T: Copy, U: Piece <T>> Piece <T> for (U,) {
type Size = U::Size;
fn construct(self) -> [T; Self::Size::N] {
self.0.construct()
}
}
And this is where problem occurs. Compiler says that Self::Size::N is an unconstrained generic constant, and tries to help with this: try adding a 'where' bound using this expression: 'where [(); Self::Size::N]:', but this is just useless.
Can anyone explain me what is going on and how to fix this issue?

trait constraint on specific function rather than whole implementation

I'm trying to implement a generic struct that can take any type parameter.
struct Position<T>{
x: T,
y: T,
}
impl<T:Num> Position<T>{
fn add(&self, other: &Position<T>) -> Box<Position<T>>{
box Position{x:self.x + other.x, y:self.y + other.y}
}
fn display(&self) -> String{
"WELCOME ".to_string()
}
}
now I can define
let original_position = Position::<int>{x: 2, y:23};
let another_postion = original_position.add(&original_position);
let welcome = original_postion.display();
without any error
similarly, i can do the following without any error.
let string_position = Position::<String>{x: "x_pos".to_string(), y: "y_pos".to_string()};
now due to the Num trait constraint i cannot call the following (which is obvious ).
string_position.add(&original_position);
but,my problem is that now i cannot call the following because of the same Num trait constraint
string_position.display()
the above function has noting to do with Num type, it simply returns the string "WELCOME"
how do i need to rewrite the implemetation so that add method can be called only by Position<Num> and display can be called by any other generic implementation.
You should create separate implementations, one with the bound and the other without, like this:
impl<T:Num> Position<T>{
fn add(&self, other: &Position<T>) -> Box<Position<T>>{
box Position{x:self.x + other.x, y:self.y + other.y}
}
}
impl<T> Position<T>{
fn display(&self) -> String{
"WELCOME ".to_string()
}
}
You can see that it works here.

How to use Rust structs from other mods

I defined a structure in a separate file. When I want to use this I do something like this at the top of the file:
use other_file::StructName;
mod other_file;
When I created a function that uses
fn test(other : StructName) {};
I get a warning about using a private type, which is fixed when I use
fn test(other : other_file::StructName) {};
This requires a lot of extra typing though. I can also reexport the module with pub use but I would really like to keep it hidden.
How do I correctly include modules to save typing? The Python equivalent to what I want is
from other_file import StructName
The following code explains this in two files. It is a stripped down version of some matrix math utils.
geometry.rs:
use geometry::{Vec3};
mod geometry;
#[deriving(Eq, Clone, Show)]
pub struct Mat4 {
data : ~[f32]
}
impl Mat4 {
fn apply_Vec3(&self, other : &Vec3) -> Vec3{
let x = self.data[0] * other.x + self.data[1] * other.y + self.data[2] * other.z;
let y = self.data[4] * other.x + self.data[5] * other.y + self.data[6] * other.z;
let z = self.data[8] * other.x + self.data[9] * other.y + self.data[10]* other.z;
Vec3::new(x, y, z)
}
}
#[deriving(Eq, Clone, Show)]
pub struct Transform {
mat : Mat4
}
impl Transform {
pub fn apply_Vec3(&self, vec : &Vec3) -> Vec3 {
self.mat.apply_Vec3(vec)
}
}
transform.rs:
#[deriving(Eq, Clone, Show)]
pub struct Vec3 {
x : f32,
y : f32,
z : f32
}
impl Vec3 {
pub fn new(x : f32, y : f32, z : f32) -> Vec3 {
Vec3{x : x, y : y, z : z}
}
}
When compiling with rustc --test transform.rs I get two errors:
transform.rs:25:39: 25:43 warning: private type in exported type signature, #[warn(visible_private_types)] on by default
transform.rs:25 pub fn apply_Vec3(&self, vec : &Vec3) -> Vec3 {
^~~~
transform.rs:25:48: 25:52 warning: private type in exported type signature, #[warn(visible_private_types)] on by default
transform.rs:25 pub fn apply_Vec3(&self, vec : &Vec3) -> Vec3 {
^~~~
I'm assuming that you're actually returning an other_file::StructName; you wouldn't get that warning otherwise.
The problem is that from somewhere else, you can't actually access the type for other_file::StructName. As you are accessing it, I presume that StructName is public, but that's not enough for things outside this module to access it: the module other_file needs to be public as well.
Replace
mod other_file;
with
pub mod other_file;
Your use statement is correct and does indeed correspond to the Python from x import y statement. (Approximately only; it's an absolute path unless self or super come into it—those that would be .foo or ..foo in Python.)
In Rust, everything is private by default with only a few exceptions; see Visibility and Privacy in the docs for more information. So, the problem is perhaps that your struct StructName is private to the other_file module.
If you declare the struct as public in b.rs:
pub struct StructName {x: int, y: int}
You can successfully use it in a.rs as you wrote:
use b::StructName;
mod b;
fn test (s: StructName) -> int {return s.x + s.y;}
fn main () {
let s = StructName {x: 1, y: 2};
let t = test (s);
println! ("{:i}", t);
}
This successfully compiles with Rust 0.9 and outputs 3.

Resources