Find out what type my class is being converted to for comparisons

2022-10-18 Thread Matthew Rushworth via Digitalmars-d-learn
I am in the process of building a matrix class (uni project, with 
my choice of programming language) and appear to have run into a 
problem that I'm not too sure how to fix.


My class uses templates to define the shape of the matrix, 
although I'm not sure if that matters. As part of my class, I 
included a opEquals, but when I try to assert that a matrix 
created by multiplying with the identity matrix matches the 
output (I checked with liberal writeln()s to make sure they do) 
but my opEquals() function (I moved it out of the class as I kept 
getting errors saying it was supposed to be non-const, and 
couldn't figure out how to fix that either) just isn't called.


---

Matrix code (the only bit of the class used by opEquals):

```
class Matrix(size_t X, size_t Y = X){
const size_t x_length = X;
const size_t y_length = Y;

double[X*Y] data;

...
}
```

The entirety of opEquals:

```
/// both matrices have to have an identical shape to compare
/// each element must be identical to match
bool opEquals(size_t X, size_t Y)(const Matrix!(X,Y) m1, const 
Matrix!(X,Y) m2) {
for (int i = 0; i < m1.data.length; ++i) if (m1.data[i] != 
m2.data[i]) return false;

return true;
}
```

and the code that excepts:

```
void main() {
auto m = new Matrix!(2)();
m.data = [1.0,0.0,0.0,1.0].dup;
auto n = new Matrix!(2)();
n.data = [2.0,3.0,4.0,5.0].dup;

auto u = mult(m,n);
writeln("u.data vs n.data:");
for (int i = 0; i < u.data.length; ++i)
writeln(u.data[i], "\t", n.data[i]);


// using opEquals() directly is working, but it doesn't 
seem to be being used
//assert(opEquals(u,n),"\"opEquals(u, n)\" is failing."); 
// this works fine
assert(u == n,"\"u == n\" is failing."); // this fails. 
Why?

}
```

---

Any help would be very much appreciated. A way to figure out what 
the '==' is converting its arguments to would also be great, but 
I'm not sure it exists (beyond just sitting down and trying to 
work it out myself, of course)


Re: Find out what type my class is being converted to for comparisons

2022-10-18 Thread rikki cattermole via Digitalmars-d-learn

Well its not a type system issue.

Making u = n, that'll returns true.

So the problem almost certainly lies with IEEE-754.
They are horrible to compare (float/double).

Unfortunately you are stuck calling functions like isClose to compare.

https://dlang.org/phobos/std_math_operations.html#.isClose

Full code extracted from above:

```d
import std;

void main()
{
auto m = new Matrix!(2)();
m.data = [1.0, 0.0, 0.0, 1.0].dup;
auto n = new Matrix!(2)();
n.data = [2.0, 3.0, 4.0, 5.0].dup;

auto u = mult(m, n);
writeln("u.data vs n.data:");
for (int i = 0; i < u.data.length; ++i)
writeln(u.data[i], "\t", n.data[i]);

// using opEquals() directly is working, but it doesn't seem to be 
being used
//assert(opEquals(u,n),"\"opEquals(u, n)\" is failing."); // this 
works fine

assert(u == n, "\"u == n\" is failing."); // this fails. Why?
}

class Matrix(size_t X, size_t Y = X)
{
const size_t x_length = X;
const size_t y_length = Y;

double[X * Y] data;

/// both matrices have to have an identical shape to compare
/// each element must be identical to match
bool opEquals(size_t X, size_t Y)(const Matrix!(X, Y) m1, const 
Matrix!(X, Y) m2)

{
for (int i = 0; i < m1.data.length; ++i)
if (m1.data[i] != m2.data[i])
return false;
return true;
}
}
```


Re: Find out what type my class is being converted to for comparisons

2022-10-18 Thread Matthew Rushworth via Digitalmars-d-learn
On Tuesday, 18 October 2022 at 18:59:37 UTC, rikki cattermole 
wrote:

Well its not a type system issue.

Making u = n, that'll returns true.

So the problem almost certainly lies with IEEE-754.
They are horrible to compare (float/double).

Unfortunately you are stuck calling functions like isClose to 
compare.


https://dlang.org/phobos/std_math_operations.html#.isClose



Hi Rikki, thanks for the rapid reply.

I'm not so sure it isn't a type issue, tbh. The only reason being 
that the opEquals() works whenever I call it directly (ignoring 
the comparison of proximity to a value for the moment)

but doesn't work when I use "=="

stripped down to just the two lines that are causing issues:

```
//assert(opEquals(u,n)); // this works fine
assert(u == n); // this fails. Why?
```

I guess to put it more bluntly, I should ask "why is opEquals 
working when I call it directly, but when I try to use the 
equality check, which should be CALLING opEquals, it doesn't 
appear to do so?"


Re: Find out what type my class is being converted to for comparisons

2022-10-18 Thread ag0aep6g via Digitalmars-d-learn
On Tuesday, 18 October 2022 at 18:53:41 UTC, Matthew Rushworth 
wrote:

The entirety of opEquals:

```
/// both matrices have to have an identical shape to compare
/// each element must be identical to match
bool opEquals(size_t X, size_t Y)(const Matrix!(X,Y) m1, const 
Matrix!(X,Y) m2) {
for (int i = 0; i < m1.data.length; ++i) if (m1.data[i] != 
m2.data[i]) return false;

return true;
}
```


A free-standing opEquals won't work. It needs to be a method of 
the class. So:


```d
class Matrix(size_t X, size_t Y = X)
{
/* ... */

bool opEquals(const Matrix m2)
{
for (int i = 0; i < this.data.length; ++i)
if (this.data[i] != m2.data[i]) return false;
return true;
}
}
```


Re: Find out what type my class is being converted to for comparisons

2022-10-18 Thread Matthew Rushworth via Digitalmars-d-learn

On Tuesday, 18 October 2022 at 20:02:02 UTC, ag0aep6g wrote:
On Tuesday, 18 October 2022 at 18:53:41 UTC, Matthew Rushworth 
wrote:

The entirety of opEquals:

```
/// both matrices have to have an identical shape to compare
/// each element must be identical to match
bool opEquals(size_t X, size_t Y)(const Matrix!(X,Y) m1, const 
Matrix!(X,Y) m2) {
for (int i = 0; i < m1.data.length; ++i) if (m1.data[i] != 
m2.data[i]) return false;

return true;
}
```


A free-standing opEquals won't work. It needs to be a method of 
the class. So:


```d
class Matrix(size_t X, size_t Y = X)
{
/* ... */

bool opEquals(const Matrix m2)
{
for (int i = 0; i < this.data.length; ++i)
if (this.data[i] != m2.data[i]) return false;
return true;
}
}
```


Thank you, that worked perfectly, not sure exactly what I did 
wrong, I'm assuming I forgot to make the parameter a const 
variable


Re: Find out what type my class is being converted to for comparisons

2022-10-19 Thread rassoc via Digitalmars-d-learn

On 10/19/22 00:43, Matthew Rushworth via Digitalmars-d-learn wrote:

Thank you, that worked perfectly, not sure exactly what I did wrong, I'm 
assuming I forgot to make the parameter a const variable


Object, the root of the class object hierarchy already defines an opEquals [1] 
and you need to overload/overwrite that for it to work properly. Only class 
methods are considered, hence ag0aep6g's suggestion.

[1] https://dlang.org/library/object/object.op_equals.html


Re: Find out what type my class is being converted to for comparisons

2022-10-19 Thread ryuukk_ via Digitalmars-d-learn
On Tuesday, 18 October 2022 at 18:53:41 UTC, Matthew Rushworth 
wrote:
I am in the process of building a matrix class (uni project, 
with my choice of programming language) and appear to have run 
into a problem that I'm not too sure how to fix.


My class uses templates to define the shape of the matrix, 
although I'm not sure if that matters. As part of my class, I 
included a opEquals, but when I try to assert that a matrix 
created by multiplying with the identity matrix matches the 
output (I checked with liberal writeln()s to make sure they do) 
but my opEquals() function (I moved it out of the class as I 
kept getting errors saying it was supposed to be non-const, and 
couldn't figure out how to fix that either) just isn't called.


---

Matrix code (the only bit of the class used by opEquals):

```
class Matrix(size_t X, size_t Y = X){
const size_t x_length = X;
const size_t y_length = Y;

double[X*Y] data;

...
}
```

The entirety of opEquals:

```
/// both matrices have to have an identical shape to compare
/// each element must be identical to match
bool opEquals(size_t X, size_t Y)(const Matrix!(X,Y) m1, const 
Matrix!(X,Y) m2) {
for (int i = 0; i < m1.data.length; ++i) if (m1.data[i] != 
m2.data[i]) return false;

return true;
}
```

and the code that excepts:

```
void main() {
auto m = new Matrix!(2)();
m.data = [1.0,0.0,0.0,1.0].dup;
auto n = new Matrix!(2)();
n.data = [2.0,3.0,4.0,5.0].dup;

auto u = mult(m,n);
writeln("u.data vs n.data:");
for (int i = 0; i < u.data.length; ++i)
writeln(u.data[i], "\t", n.data[i]);


// using opEquals() directly is working, but it doesn't 
seem to be being used
//assert(opEquals(u,n),"\"opEquals(u, n)\" is 
failing."); // this works fine
assert(u == n,"\"u == n\" is failing."); // this fails. 
Why?

}
```

---

Any help would be very much appreciated. A way to figure out 
what the '==' is converting its arguments to would also be 
great, but I'm not sure it exists (beyond just sitting down and 
trying to work it out myself, of course)


What's the reason for it being a class? struct makes more sense 
here, plus it'll be faster


If it were a struct, you'd not need any of that, and you can also 
have operator overloading for your mult while also being able to 
check how many row/col at compile time, here an example:


```D
import std;

struct Matrix(size_t X, size_t Y = X)
{
enum x_length = X; // enum so it's available only at compile 
time

enum y_length = Y;
double[X * Y] data;

// operator overloading
Matrix opBinary(string op)(Matrix rhs)
{
static if (op == "*")
{
//
// ** ADD YOUR MULT OPERATION HERE **
//
static if (X == 2)
{
return Matrix();
}
else
static assert("not supported");
}
else
static assert(0, "Operator " ~ op ~ " not 
implemented");

}
}

void main()
{
// check equality by value:
auto a = Matrix!(2)();
a.data = 0;
auto b = Matrix!(2)();
b.data = 0;

writeln("are they the same?: ", a == b); // it'll check for 
equality by value


auto m = Matrix!(2)();
m.data = [1.0, 0.0, 0.0, 1.0];
auto n = Matrix!(2)();
n.data = [2.0, 3.0, 4.0, 5.0];

// here we can use the * operator!
auto u = m * n;

writeln("u.data vs n.data:");

for (int i = 0; i < u.data.length; ++i)
writeln(u.data[i], "\t", n.data[i]);
}
```