-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Float types as parametrics #14
base: master
Are you sure you want to change the base?
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 DMatrix64
but 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).