-
Notifications
You must be signed in to change notification settings - Fork 171
Fixed printing for arrays as per CPython #1552
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
base: main
Are you sure you want to change the base?
Conversation
How would this now print in LFortran? |
Currently in LFotran , if we run a very basic program trying to print two arrays together , we have the following
So basically
|
I think LFortran should behave like GFortran by default: $ lfortran x.f90
100
200
300
400
$ gfortran x.f90
$ ./a.out
100 200 300 400 But with a command line option it would behave like this: $ lfortran --nice-print x.f90
[100, 200] [300, 400] |
Sure I'll open a Pr in LFortran soon to address this . Does the Pr here look good to you ? |
I had opened a similar issue regarding printing of arrays in Lfortran a couple of days back - lfortran/lfortran#1348 |
print(arr1, arr2) | ||
print(arr1, arr2, sep="abc") | ||
print(arr1, arr2, end="pqr\n") | ||
print(arr1, arr2, sep="abc", end="pqr\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is only limited to 1D arrays. Let's test it for 2D, 3D and 4D arrays as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I had mentioned in the PR description that currently only 1D arrays work properly (I'll highlight it for everyone) . For 2D We have the following
def main0():
Nx: i32 = 2; Ny: i32 = 2
arr: i32[2, 2] = empty([Ny, Nx], dtype=int32)
i: i32
j: i32
for i in range(Ny):
for j in range(Nx):
arr[i, j] = i * j
print(arr)
main0()
(lf) anutosh491@spbhat68:~/lpython/lpython$ ./src/bin/lpython ./examples/expr2.py
[0 0
0 1]
(lf) anutosh491@spbhat68:~/lpython/lpython$ python examples/expr2.py
[[0 0]
[0 1]]
I'll try to address n-dimensional arrays in this Pr or a subsequent PR as soon as I realize the approach for it !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's stopping us from implementing printing >= 3D arrays? Is it an algorithmic blocker? Or ASR design is insufficient to support it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem like an ASR design problem to me as of now . It's just that the current implementation of print_array_using_doloop
is tailored specifically for 1D arrays and would need to be modified to handle higher dimensions.
Getting outputs isn't a problem ( I tried for 4D and 5D too) but suppose we have the following
(lf) anutosh491@spbhat68:~/lpython/lpython$ cat examples/expr2.py
from numpy import empty, int32
def main0():
Nx: i32 = 3;
arr: i32[3, 3, 3] = empty([Nx, Nx, Nx], dtype=int32)
i: i32
j: i32
k: i32
for i in range(Nx):
for j in range(Nx):
for k in range(Nx):
arr[i, j, k] = i * j * k
print(arr)
main0()
(lf) anutosh491@spbhat68:~/lpython/lpython$ ./src/bin/lpython ./examples/expr2.py
[0 0 0
0 0 0
0 0 0
0 0 0
0 1 2
0 2 4
0 0 0
0 2 4
0 4 8
]
(lf) anutosh491@spbhat68:~/lpython/lpython$ python examples/expr2.py
[[[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 1 2]
[0 2 4]]
[[0 0 0]
[0 2 4]
[0 4 8]]]
Here print_array_using_doloop
is only responsible for printing the elements out , without any formatting .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what comes to my mind currently is that we recursively keep cutting down a dimension in visit_Print
and keep printing the 1D array which we would obtain finally (as 1D arrays are being printed perfectly) . This can be done here
+++ b/src/libasr/pass/print_arr.cpp
@@ -150,6 +150,12 @@ public:
print_body.clear();
}
pass_result.push_back(al, print_open_bracket);
+ int n_dims = PassUtils::get_rank(x.m_values[i]);
+ if (n_dims > 1) {
+ // Create a print object having a subarray reference
+ // with a lesser dimension than what we have originally
+ // and call visit_Print on it .
+ }
print_stmt = print_array_using_doloop(x.m_values[i], x.base.base.loc);
We might need to frame a ASR::expr_t* create_subarray_ref(ASR::expr_t* arr_expr, int dim_idx, int dim_size, Allocator& al)
or something for this just like we have create_array_ref
!
However, this approach can lead to a large number of nested calls, which may impact performance !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's see. How would you write a C function for printing arrays of general N-dimensions using only loops? Once that figured out then translating that C code into ASR should be easy then.
However, this approach can lead to a large number of nested calls, which may impact performance !
Well if you are talking about recursive approach to print array then also follow the same approach, write code in C to print arrays of general N dimensions and then translate it into ASR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay , not sure how I could get it translated into ASR but a C function which is recursive and also takes care of formatting would be the following
#include <stdio.h>
void print_array(int *arr, int *shape, int ndim) {
printf("[");
for (int i = 0; i < shape[0]; i++) {
if (ndim > 1) {
print_array(arr + i * shape[1], shape + 1, ndim - 1);
} else {
printf("%d", arr[i]);
}
if (i < shape[0] - 1) {
printf(" ");
}
}
printf("]\n");
}
int main() {
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int shape[] = {2, 3};
print_array((int *) arr, shape, 2);
return 0;
}
This would give us
[[1 2 3]
[4 5 6]]
This would require the array , ndim and the size along each dimension !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Now there are two ways to deal with this,
- Include your printing function in C backend and call it from LLVM/C backend.
- Following this approach in ASR would be very tricky as you are dealing with pointers directly. However the pattern I see here is printing each row in a new line with opening brackets and spaces prefixed and some closing brackets suffixed. Correct? If so, then I guess it can done using nested loops. Consider the following example,
>>> arr = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
>>> arr
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
Printing using loops (algorithm not exact code and row major order printing) would like,
do i = 1, 2
do j = 1, 2
do k = 1, 3
if k < 3 then
print *, arr[i, j, k], ", "
else
print *, arr[i, j, k], "]"
end if
end do
print *, "\n"
end do
print *, "]\n"
end do
print *, "]\n"
Add an extra closing bracket for each loop (except the innermost). Note that while generating code for printing you know the dimensions of array being printed at compile time. If the dimensions are not known (say the output of reshape is being printed then print it in a single line).
This is a Pr in succession to #1512. Currently I've added support for 1d arrays .
For something like the following
On main
On branch (as expected through CPython)