Conversation
|
Thank you for taking time to do this refactoring. There are, unfortunately, two things that I do not like about it. For one thing, you removed all Second, this makes As such, I am not sure I am going to merge this. On the other hand, if this massively simplifies the implementation by reducing the duplication, it may be worth it. Let's discuss it a bit. By the way, I have a prototype neural network implementation based on this library, and it has its fair share of duplication. I am going to open it in the next days, so may be it will be a good starting point to see the effect of this change in concrete |
|
By the way, I see that you moved all constraints to the types definitions. I had missed that, so part of what I said above does not make sense. For some reason, I always found issues in the compiler when putting type constraints there - this is why I was putting them in functions. I will experiment a bit with your new version, and let you know any other comment I have |
|
Just to make sure, the type definition currently is: type
Vector*[N: static[int], T: SomeReal] = ref array[N, T]
Matrix*[M, N: static[int], T: SomeReal] = object
order: OrderType
data: ref array[N * M, T]Regarding your first point, For your second point, Is that OK for both? Regarding the generalization to |
|
Bad news, I realized that when launching tests I was importing the working linalg library instead of my modifications. It seemed to good to be true to pass all the tests whatever I did. So I will probably have to rework my commits from scratch. |
|
I've reset the branch to rework from scratch while making sure I load the WIP version with the test suite. I'll keep the With the current very minimal modifications, I fail the following tests: funcs.nim funcs.nim(26, 18) Error: type mismatch: got (Matrix64[2, 2], Matrix64[2, 1])
but expected one of:
proc solve[M, N: static[int]](a: Matrix32[M, M]; b: Matrix32[M, N]): Matrix32[M, N]
proc solve[M: static[int]](a: Matrix32[M, M]; b: Vector32[M]): Vector32[M]
proc solve[M, N: static[int]](a: Matrix64[M, M]; b: Matrix64[M, N]): Matrix64[M, N]
proc solve[M: static[int]](a: Matrix64[M, M]; b: Vector64[M]): Vector64[M]
|
|
Regarding the solve issue, I've reproduced a minimum test case. It seems like compiler bug nim-lang/Nim#4554: import linalg
let a = matrix(@[
@[3.0, 1.0],
@[1.0, -2.0]
], 2, 2)
let b = matrix(@[@[1.0],
@[0.0]],
2, 1)
#let x = a.solve(b)
proc test*(a: Matrix64, b: Matrix64) =
echo a
echo b
test(a,a) #works
test(b,b) #works
test(a,b) #fails
Error: type mismatch: got (Matrix64[2, 2], Matrix64[2, 1])
but expected one of:
proc test[Matrix64](a: Matrix64; b: Matrix64) |
|
Oh, I am sorry to hear that, but in fact I was surprised that the compiler allowed type constraints in the type declaration section. I think you should be good just by running Regarding the compiler issues with Let me know if I can be of any help |
|
For now I'm stuck as all types of workarounds for the import linalg
let a = matrix(@[
@[3.0, 1.0],
@[1.0, -2.0]
], 2, 2)
let b = matrix(@[@[1.0],
@[0.0]],
2, 1)
#let x = a.solve(b)
proc test*[M,N: static[int]](a: Matrix64[M,N], b: Matrix64[M,N]) =
echo a
echo b
test(a,a) #works
test(b,b) #works
#test(a,b) # fails type mismatch
#Error: type mismatch: got (Matrix64[2, 2], Matrix64[2, 1])
#but expected one of:
#proc test[M, N](a: Matrix64[M, M]; b: Matrix64[M, N])
echo "Test #1 DONE"
proc test2*[M,N: static[int]](a: Matrix64[M,M], b: Matrix64[M,N]) =
echo a
echo b
test2(a,a) #works
#test2(b,b) #b is [2,1], dim error should be catched by Nim but it's catched by clang
#Error: execution of an external compiler program 'clang -c -w -I/usr/local/Cellar/nim/HEAD-875e344/nim/lib -o nimcache/linalg_playground.o nimcache/linalg_playground.c' failed with exit code: 1
#nimcache/linalg_playground.c:495:31: error: passing 'Matrix_zhuhOuhVfbLJLsmoc8sThg' (aka 'struct Matrix_zhuhOuhVfbLJLsmoc8sThg') to parameter of incompatible type 'Matrix_4UORjnPzvIMBohnnojhPgw' (aka 'struct Matrix_4UORjnPzvIMBohnnojhPgw')
# test2_A4PrUCOWHf2urCkKnNhZzg(b_ONM9cc62rV8Rg9cSV3Ca9c3lA, b_ONM9cc62rV8Rg9cSV3Ca9c3lA);
# ^~~~~~~~~~~~~~~~~~~~~~~~~~~
#nimcache/linalg_playground.c:400:77: note: passing argument to parameter 'a' here
#N_NIMCALL(void, test2_A4PrUCOWHf2urCkKnNhZzg)(Matrix_4UORjnPzvIMBohnnojhPgw a, Matrix_zhuhOuhVfbLJLsmoc8sThg b) {
# ^
#1 error generated.
echo "Test #2 DONE"
proc test3*[M,N: static[int], T](a: Matrix[M,N,T], b: Matrix[M,N,T]) =
echo a
echo b
test3(a,a) #fails
#Error: ambiguous call; both linalg.$(m: Matrix32[$.M, $.N]) and linalg.$(m: Matrix64[$.M, $.N]) match for: (Matrix[2, 2])
#test3(a,b) #same failure as just above
echo "Test #3 DONE"For the last part, it seems like proc `$`*[M, N: static[int]](m: Matrix32[M,N] or Matrix64[M,N]): string =
result = "[ "
for i in 0 .. < M - 1:
result &= toStringHorizontal(m.row(i)) & "\n "
result &= toStringHorizontal(m.row(M - 1)) & " ]"Alas I get caught in overloading resolution issues with system.$ Error: ambiguous call; both system.$(x: T) and linalg.$(m: Matrix[$.M, $.N, $.T] or Matrix32[$.M, $.N]) match for: (Matrix64[2, 2])Resolution order
I thought nim-lang/Nim#1991 regarding type class overloading and fixed 16 hours ago would help but unfortunately no. When trying to completely remove Matrix32 and Matrix64 and use the new underlying Matrix, I get hit with static bug: proc `$`*[M, N: static[int], T](m: Matrix[M, N, T]): string =
result = "[ "
for i in 0 .. < M - 1:
result &= toStringHorizontal(m.row(i)) & "\n "
result &= toStringHorizontal(m.row(M - 1)) & " ]"
I have yet to try the syntax mentioned in the bug nim-lang/Nim#1991 but it will probably need generic generic parameters https://github.com/nim-lang/Nim/issues/3856 |
|
Opened nim-lang/Nim#5641, nim-lang/Nim#5643, nim-lang/Nim#5644 Edit nim-lang/Nim#5645 as well |
|
Thank you! |
|
Following the resolution of almost all Nim related issues, I have now a minimal working rewrite. Now all remaining procs can be converted one by one. |
|
It is great to hear that this is now working! I am not sure what problems |
|
As mentioned in the README, an expanded rewrite is here |
This is work in progress to solve: #5
This feature is key to implement machine learning algorithms without code duplication for float32, float64 and float (pointer-sized, 32 bits on 32-bit, 64 bits on 64-bit machine)
A lesser alternative is exporting
AnyMatrix = Matrix32 or Matrix64 or DMatrix32 or DMatrix64but the proc will lose dimension information.Furthermore should Nim or a library implement half-precision float16 in the future, supporting it would be trivial. (float16 allows 2x TFLOPS on some hardware).