certik / minpack

Library for solving nonlinear equations and nonlinear least squares problems
http://www.netlib.org/minpack/
Other
32 stars 10 forks source link

LLVM codegen error: example_lmder1.f90 #11

Open Smit-create opened 1 year ago

Smit-create commented 1 year ago

The error comes from: https://github.com/certik/minpack/blob/12f30bc2d6971fde7a32d59e80c635289376e14a/examples/example_lmder1.f90#L67

Error:

code generation error: asr_to_llvm: module failed verification. Error:
FPExt only operates on FP
  %169 = fpext %array.2* %x to double
Smit-create commented 1 year ago

Commenting out that only that line, we get another error codegen error:

std::vector<llvm::Value *> args2 = convert_call_args(x, m_name);
  File "/Users/thebigbool/repos2/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 5641
    LFORTRAN_ASSERT(finder != nested_globals.end());
AssertFailed: finder != nested_globals.end()

This error is because of the following line: call chkder(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), xp, fvecp, 1, err)

To make this compile, I use the following diff:

diff --git a/examples/example_lmder1.f90 b/examples/example_lmder1.f90
index 984207e..2ccadaa 100644
--- a/examples/example_lmder1.f90
+++ b/examples/example_lmder1.f90
@@ -64,7 +64,7 @@ tol = sqrt(epsilon(1._dp))
 allocate(wa(5*size(x) + size(fvec)))
 call lmder1(fcn, size(fvec), size(x), x, fvec, fjac, size(fjac, 1), tol, &
     info, ipvt, wa, size(wa))
-print 1000, enorm(size(fvec), fvec), info, x
+!print *, enorm(size(fvec), fvec), info, x
 1000 format(5x, 'FINAL L2 NORM OF THE RESIDUALS', d15.7 // &
             5x, 'EXIT PARAMETER', 16x, i10              // &
             5x, 'FINAL APPROXIMATE SOLUTION'            // &
@@ -74,8 +74,11 @@ contains

 subroutine check_deriv()
 real(dp) :: xp(size(x)), fvecp(size(fvec)), err(size(fvec))
-call chkder(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), xp, fvecp, &
-    1, err)
+integer :: a, b, c
+a = size(fvec)
+b = size(x)
+c = size(fjac, 1)
+call chkder(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), xp, fvecp, 1, err)
 call fcn(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), 1)
 call fcn(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), 2)

and that did compile fine with some linker errors as in #10

Smit-create commented 1 year ago

Another issue:

program example_lmder1

integer :: a = 10
real :: b(2)

call foo()

contains

subroutine foo()
call fo2(size(b), b)
end subroutine

subroutine fo2(m, vec)
    integer :: m, vec(m)
    print *, m
end subroutine

end program

Output:

code generation error: b isn't defined in any scope.
Smit-create commented 1 year ago

With https://github.com/lfortran/lfortran/pull/1035, I am able to compile this example with the following diff:

diff --git a/examples/example_lmder1.f90 b/examples/example_lmder1.f90
index 984207e..43f69b8 100644
--- a/examples/example_lmder1.f90
+++ b/examples/example_lmder1.f90
@@ -64,7 +64,8 @@ tol = sqrt(epsilon(1._dp))
 allocate(wa(5*size(x) + size(fvec)))
 call lmder1(fcn, size(fvec), size(x), x, fvec, fjac, size(fjac, 1), tol, &
     info, ipvt, wa, size(wa))
-print 1000, enorm(size(fvec), fvec), info, x
+print *, dabs(1.0)
+!print 1000, enorm(size(fvec), fvec), info, x

It runs and then fails with a segmentation fault after a few steps.

Smit-create commented 1 year ago

@certik With the diff in https://github.com/certik/minpack/issues/11#issuecomment-1326495258, I am now able to compile and run example_lmder.f90 successfully with the current main branch of lfortran. It fails with a segmentation fault later on during execution after some steps. One probable issue is the following:

program main

integer :: b(2)

b = [244, 1404]

call foo()

contains

subroutine foo()
    b(1) = 43
    b(2) = 15
call foo2(size(b), b)
end subroutine

subroutine foo2(m, vec)
    integer :: m, vec(m)
    print *, m, vec(1), vec(2)
end subroutine

end program

LFortran Output:

% lfortran a.f90 
2 15 77306806
% lfortran a.f90
2 15 11443126
% lfortran a.f90
2 15 37153718

gfortran output:

% gfortran a.f90 && ./a.out 
           2          43          15

There is probably something wrong with the assignments as the following foo2 works fine(which is a bug):

subroutine foo2(m, vec)
    integer :: m, vec(m)
    print *, m, vec(0), vec(1)
end subroutine

LFortran output:

% lfortran a.f90           
2 43 15
% lfortran a.f90
2 43 15
% lfortran a.f90
2 43 15
certik commented 1 year ago

Thanks for this. I'll have a look.

certik commented 1 year ago

I can reproduce the bug, so I reported it here: https://github.com/lfortran/lfortran/issues/1051

This bug is not needed for minpack, as SciPy doesn't use this code. I wrote it myself to test minpack, but if LFortran can't do it yet, then we don't need to worry.

To fix these parent scope bugs, I recommend to implement nested lambda functions in LFortran first, which @rebcabin and I have been slowly working towards. We have to fix this properly at the ASR level (one way or the other), then this will start working well. Right now these parent scopes are handled in the LLVM backend directly and I know there are bugs and it's very hard to maintain.

Pranavchiku commented 1 year ago

@certik @Smit-create for example in comment, b is initialised only for two integer values, that means it can hold values at two indices i.e. b(0), b(1) and if tried to access b(2) will always throw junk ( which is observed in lfortran ). I am wondering why assignment b(2) = 15 allowed in gfortran and lfortran, shouldn't it throw accessing out of bounds error?

Pranavchiku commented 1 year ago

Okay so, by the following diff I am able to compile example_lmder1.f90 without segmentation fault.

diff --git a/examples/example_lmder1.f90 b/examples/example_lmder1.f90
index 984207e..9414dfe 100644
--- a/examples/example_lmder1.f90
+++ b/examples/example_lmder1.f90
@@ -34,7 +34,7 @@ else
         tmp4 = (x(2)*tmp2 + x(3)*tmp3)**2
         fjac(i,1) = -1.D0
         fjac(i,2) = tmp1*tmp2/tmp4
-        fjac(i,3) = tmp1*tmp3/tmp4
+        ! fjac(i,3) = tmp1*tmp3/tmp4
     end do
 end if
 end subroutine
Smit-create commented 1 year ago

@certik @Smit-create for example in comment, b is initialised only for two integer values, that means it can hold values at two indices i.e. b(0), b(1) and if tried to access b(2) will always throw junk ( which is observed in lfortran ). I am wondering why assignment b(2) = 15 allowed in gfortran and lfortran, shouldn't it throw accessing out of bounds error?

Arrays in Fortran have 1-based indexing. And so b(2) is fine but not b(0).

Pranavchiku commented 1 year ago

Okay so, I observed following difference in the output for example_lmder1.f90 with diff

@@ -54,7 +57,9 @@ real(dp), allocatable :: wa(:)

 ! The following starting values provide a rough fit.
 x = [1._dp, 1._dp, 1._dp]
-
+print *, "fvec size: ", size(fvec)
+print *, "size of x : ", size(x)
+print *, "ldfjac initial: ", size(fjac,1)
 call check_deriv()

Gfortran

 fvec size:           15
 size of x :            3
 ldfjac initial:           15
 ldfjac:           15
 n:            3
 ldfjac:           15
 n:            3
 ldfjac:           15
 n:            3
 Derivatives check (1.0 is correct, 0.0 is incorrect):
  0.34167772409443192       0.26609177862398736       0.22240032976470067       0.19230769261632810       0.16877864079222862       0.15028146168632606       0.13485790624604307       0.12117537236197391       0.11482694121292628        9.9569409124501615E-002   8.9102784011035108E-002   7.8383378719671506E-002   6.7451393119264111E-002   5.5987673912383733E-002   4.3547993352560439E-002
 ldfjac here:           15
 ldfjac:           15
 n:            3
 ldfjac:           15
 n:            3
 ldfjac:           15
 n:            3
 ldfjac:           15
 n:            3
   3.0000000000000000     
 here

LFortran


fvec size:  15
size of x :  3
ldfjac initial:  45
ldfjac:  45
n:  3
ldfjac:  45
n:  3
ldfjac:  45
n:  3
Derivatives check (1.0 is correct, 0.0 is incorrect):
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00
0.00000000000000000e+00

ldfjac here: 45 ldfjac: 45 n: 3 ldfjac: 45 n: 3 ldfjac: 45 n: 3 3.00000000000000000e+00 here



Values start to diverge just after declaration of variables in `program example_lmder1` this may lead to `segmentation fault`.
Pranavchiku commented 1 year ago

Error in comment 1 might be because of below given case

program main

integer :: x(3)
x(1) = 1    
x(2) = 2
x(3) = 3
print *, "x :", x

end program

LFortran output:

lfortran a.f90
x : -1989596352

GFortran output:

gfortran a.f90 && ./a.out
 x :           1           2           3
program main

integer :: x(3)
integer b
x(1) = 1    
x(2) = 2
x(3) = 3
b = 10
print *, b, x

end program

LFortran output:

lfortran a.f90
10 -709536896
lfortran a.f90
10 -1272557600
lfortran a.f90
10 -1203966432

GFortran output:

gfortran a.f90 && ./a.out
10           1           2           3
Pranavchiku commented 1 year ago

Whereas

program main
integer :: x(3)
integer b
x(1) = 1    
x(2) = 2
x(3) = 3
b = 10
print *, x
end program

Gives same output as gfortran.

certik commented 1 year ago

The last example is this bug: https://github.com/lfortran/lfortran/issues/1112.

Pranavchiku commented 1 year ago

Issue for comment, lfortran/lfortran#1133

Pranavchiku commented 1 year ago

Okay so, here I can observe one cause of the divergence of values.

LFortran

[100%] Built target example_lmder1
3.00000000000000000e+00
check deriv before
ldfjac initial:  45
chkder
fvec
in chkder
epsmch =  2.22044604925999980e-16
eps =  1.49011611938801578e-08
mode =  1
n =  3
j =  1
temp =  1.49011611938801578e-08
xp(j) =  0.00000000000000000e+00
after xp(j) =  1.00000001490116119e+00
j =  2
temp =  1.49011611938801578e-08
xp(j) =  0.00000000000000000e+00
after xp(j) =  1.00000001490116119e+00
j =  3
temp =  1.49011611938801578e-08
xp(j) =  0.00000000000000000e+00
after xp(j) =  1.00000001490116119e+00
out of chkder
calling fcn
y(i) =  1.40000000000000013e-01
x(1) =  1.00000000000000000e+00
x(2) =  1.00000000000000000e+00
x(3) =  1.00000000000000000e+00
fvec(i) =  -9.22499999999999987e-01
y(i) =  1.79999999999999993e-01
x(1) =  1.00000000000000000e+00
x(2) =  -9.22499999999999987e-01
x(3) =  1.00000000000000000e+00
fvec(i) =  -6.36765918460833635e-01
y(i) =  2.20000000000000001e-01
x(1) =  1.00000000000000000e+00
x(2) =  -9.22499999999999987e-01
x(3) =  -6.36765918460833635e-01
fvec(i) =  -5.64216094286594805e-01
y(i) =  2.50000000000000000e-01
x(1) =  1.00000000000000000e+00
x(2) =  -9.22499999999999987e-01
x(3) =  -6.36765918460833635e-01
fvec(i) =  -4.56250914601839197e-01
y(i) =  2.89999999999999980e-01
x(1) =  1.00000000000000000e+00
x(2) =  -9.22499999999999987e-01
x(3) =  -6.36765918460833635e-01
fvec(i) =  -3.34943636313187298e-01
y(i) =  3.20000000000000007e-01
x(1) =  1.00000000000000000e+00
x(2) =  -9.22499999999999987e-01
x(3) =  -6.36765918460833635e-01

GFortran

[100%] Built target example_lmder1
3.0000000000000000     
check deriv before
ldfjac initial:           15
chkder
fvec
in chkder
epsmch =    2.2204460492599998E-016
eps =    1.4901161193880158E-008
mode =            1
n =            3
j =            1
temp =    1.4901161193880158E-008
xp(j) =    0.0000000000000000     
after xp(j) =    1.0000000149011612     
j =            2
temp =    1.4901161193880158E-008
xp(j) =    0.0000000000000000     
after xp(j) =    1.0000000149011612     
j =            3
temp =    1.4901161193880158E-008
xp(j) =    0.0000000000000000     
after xp(j) =    1.0000000149011612     
out of chkder
calling fcn
y(i) =   0.14000000000000001     
x(1) =    1.0000000000000000     
x(2) =    1.0000000000000000     
x(3) =    1.0000000000000000     
fvec(i) =  -0.92249999999999999     
y(i) =   0.17999999999999999     
x(1) =    1.0000000000000000     
x(2) =    1.0000000000000000     
x(3) =    1.0000000000000000     
fvec(i) =  -0.94500000000000006     
y(i) =   0.22000000000000000     
x(1) =    1.0000000000000000     
x(2) =    1.0000000000000000     
x(3) =    1.0000000000000000     
fvec(i) =  -0.96750000000000003     
y(i) =   0.25000000000000000     
x(1) =    1.0000000000000000     
x(2) =    1.0000000000000000     
x(3) =    1.0000000000000000     
fvec(i) =   -1.0000000000000000     
y(i) =   0.28999999999999998     
x(1) =    1.0000000000000000     
x(2) =    1.0000000000000000     
x(3) =    1.0000000000000000     
fvec(i) =   -1.0225000000000000     
y(i) =   0.32000000000000001     
x(1) =    1.0000000000000000     
x(2) =    1.0000000000000000     
x(3) =    1.0000000000000000     
Pranavchiku commented 1 year ago

This is a separate bug, lfortran/lfortran#1150