HP Forums
(Recursive) nested loops and IFs? - Printable Version

+- HP Forums (https://www.hpmuseum.org/forum)
+-- Forum: HP Calculators (and very old HP Computers) (/forum-3.html)
+--- Forum: HP Prime (/forum-5.html)
+--- Thread: (Recursive) nested loops and IFs? (/thread-5351.html)



(Recursive) nested loops and IFs? - chromos - 12-17-2015 07:17 AM

Hi,
I'm writting solver for incomplete coordinates for multi caches (is there any geocacher out there?) which solves (brute force) inequalities, but their quantity and number of variables (and their names) is obtained from user via INPUT.

For six inequalities and four variables I have this static code:
(L1...coords via user input, something like {"5","0","3","5","(A+1)","(B)","(B-A-4)","0","1","5","2","4","(C-14)","(D-8)","(C-D+3)"}
L2...List of variable names,
L3, L4...Lists of variable boundaries,
L5...List of expressions
L6...valid variable values
Digitsum... digit sum of whole coordinates)

PHP Code:
SUBRFROMTO()
BEGIN
FOR Loop1 FROM L3(1TO L4(1) DO
 PRINT(); 
 PRINT(
"



                        Completed: "
+(Loop1*100/(L4(1)-L3(1)))+" %");
 FOR 
Loop2 FROM L3(2TO L4(2) DO
  FOR 
Loop3 FROM L3(3TO L4(3) DO
   FOR 
Loop4 FROM L3(4TO L4(4) DO
    
TempList:={};
    FOR 
Loop FROM 1 TO SIZE(L2) DO
     
EXPR(L2(Loop)+":=Loop"+STRING(Loop));
     
TempList(0):=EXPR(L2(Loop));
    
END;
    
Temp:=0;
    IF 
DigitSum>0 THEN
     
FOR Loop FROM 1 TO SIZE(L5) DO
      
Temp:=Temp+EXPR(L5(Loop));
     
END;
    
END;
    IF (
NOT(DigitSum>0) OR Temp==DigitSum-SubDigitSumTHEN
     
IF (EXPR(L5(1))>=AND EXPR(L5(1))<=9THEN
      
IF (EXPR(L5(2))>=AND EXPR(L5(2))<=9THEN
       
IF (EXPR(L5(3))>=AND EXPR(L5(3))<=9THEN
        
IF (EXPR(L5(4))>=AND EXPR(L5(4))<=9THEN
         
IF (EXPR(L5(5))>=AND EXPR(L5(5))<=9THEN
          
IF (EXPR(L5(6))>=AND EXPR(L5(6))<=9THEN
           L8
(0):=""+EXPR(L1(1))+EXPR(L1(2))+"° "+EXPR(L1(3))+EXPR(L1(4))+"."+EXPR(L1(5))+EXPR(L1(6))+EXPR(L1(7));
           
L9(0):=""+EXPR(L1(8))+EXPR(L1(9))+EXPR(L1(10))+"° "+EXPR(L1(11))+EXPR(L1(12))+"."+EXPR(L1(13))+EXPR(L1(14))+EXPR(L1(15));
           
L6(0):=TempList;
           
Dist:=acos(sin(PublLat)*sin(FUNCDMTODEG(L8(SIZE(L8))))+cos(PublLat)*cos(FUNCDMTODEG(L8(SIZE(L8))))*cos(FUNCDMTODEG(L9(SIZE(L9)))-PublLon));
           
IFERR(acos((sin(FUNCDMTODEG(L8(SIZE(L8))))-sin(PublLat)*cos(Dist))/(sin(Dist)*cos(PublLat)))) THEN
            L0
(0):=ROUND(6371*π/180*Dist,-3)+" km  error°";
           ELSE
            
θ:=360-acos((sin(FUNCDMTODEG(L8(SIZE(L8))))-sin(PublLat)*cos(Dist))/(sin(Dist)*cos(PublLat)));
            
L0(0):=ROUND(6371*π/180*Dist,-3)+" km  "+ROUND(θ,0)+"°";
           
END;
          
END;
         
END;
        
END;
       
END;
      
END;
     
END;
    
END;
   
END;
  
END;
 
END;
END;
END

I tried to build it recursively, but this is my first encounter with recursion so I can't find syntax which works.

I tried it with another approach where I packed everything as text and then I execute it via EXPR(...) and it works. Dissadvantage is unreadable code and everything must be in one string otherwise FOR and END will collapse.

Can anybody show me how build nested loops and IFs if I don't know their quantity beforehand?

Some screenshots:
[attachment=2967][attachment=2968][attachment=2969][attachment=2970][attachment=2971]


RE: (Recursive) nested loops and IFs? - chromos - 12-17-2015 07:28 AM

[attachment=2972] Because there is five attachments limit, I give program for interested people into this post.
(Programm counts distance and bearing correctly for North East hemisphere and can solve for six inequalities and four variables only.)


RE: (Recursive) nested loops and IFs? - Didier Lachieze - 12-17-2015 11:50 AM

You can replace the nested IFs with a single IF which will work for any size of L5.

Replace:
Code:

     IF (EXPR(L5(1))>=0 AND EXPR(L5(1))<=9) THEN
      IF (EXPR(L5(2))>=0 AND EXPR(L5(2))<=9) THEN
       IF (EXPR(L5(3))>=0 AND EXPR(L5(3))<=9) THEN
        IF (EXPR(L5(4))>=0 AND EXPR(L5(4))<=9) THEN
         IF (EXPR(L5(5))>=0 AND EXPR(L5(5))<=9) THEN
          IF (EXPR(L5(6))>=0 AND EXPR(L5(6))<=9) THEN
           [...]
          END;
         END;
        END;
       END;
      END; 
     END;

By:
Code:

     IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9",L5)) THEN
       [...]
     END;

Thanks for publishing your program, do you have some data samples that could be used to test it?


RE: (Recursive) nested loops and IFs? - chromos - 12-17-2015 12:15 PM

Thank you Didier, I'll try your code.

I am testing my program on this cache:

Bysterske vyhlidky

This is unfortunately in czech language so importatnt data are:

Coords to solve:
N 50°35.(A+1) (B) (B-A-4)
E 015°24.(C-14) (D-8) (C-D+3)

Enter it as showed (without N and E letters and without ° character and without parentheses).

Digit sum for solved coords is 49.

Starting published coordinates are:
N 50° 36.404 E 015° 24.120
Enter it as showed (without N and E letters and without ° character).

I don't know if you are geocacher, so expressions in parentheses aren't multiplied with each other. Instead of, every pair of parentheses is one digit to solve.

Meanwhile I updated my program (for example there wasn't handled case when no coords were found.
[attachment=2974]


RE: (Recursive) nested loops and IFs? - Didier Lachieze - 12-17-2015 04:17 PM

Here is a way to replace the nested loops by a single one using a list (LoopIdx) to store the different loop index values. LoopIdx is replacing Loop1, Loop2, Loop3 & Loop4 and allows for a dynamic number of variables as it is sized according to the size of your L3.
This is based on the latest version of your program:

PHP Code:
SUBRFROMTO()
BEGIN
 LOCAL n
IdxLoopIdxs;
 PRINT(); 
 PRINT(
"



                        Completed: 0 %"
);
LoopIdx:=L3;
s:=SIZE(L3);
FOR 
Idx FROM 1 TO ΠLIST(L4-L3) DO
  
TempList:={};
  FOR 
Loop FROM 1 TO SIZE(L2) DO
   
EXPR(L2(Loop)+":=LoopIdx("+STRING(Loop)+ ")");
   
TempList(0):=EXPR(L2(Loop));
  
END;
  
Temp:=0;
  IF 
DigitSum>0 THEN
   
FOR Loop FROM 1 TO SIZE(L5) DO
    
Temp:=Temp+EXPR(L5(Loop));
   
END;
  
END;
  IF (
NOT(DigitSum>0) OR Temp==DigitSum-SubDigitSumTHEN
   
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9",L5)) THEN
    L8
(0):=""+EXPR(L1(1))+EXPR(L1(2))+"° "+EXPR(L1(3))+EXPR(L1(4))+"."+EXPR(L1(5))+EXPR(L1(6))+EXPR(L1(7));
    
L9(0):=""+EXPR(L1(8))+EXPR(L1(9))+EXPR(L1(10))+"° "+EXPR(L1(11))+EXPR(L1(12))+"."+EXPR(L1(13))+EXPR(L1(14))+EXPR(L1(15));
    
L6(0):=TempList;
    
Dist:=acos(sin(PublLat)*sin(FUNCDMTODEG(L8(0)))+cos(PublLat)*cos(FUNCDMTODEG(L8(0)))*cos(FUNCDMTODEG(L9(0))-PublLon));
    
IFERR(acos((sin(FUNCDMTODEG(L8(0)))-sin(PublLat)*cos(Dist))/(sin(Dist)*cos(PublLat)))) THEN
     L0
(0):=ROUND(6371*π/180*Dist,-3)+" km  error°";
    ELSE
     
θ:=360-acos((sin(FUNCDMTODEG(L8(0)))-sin(PublLat)*cos(Dist))/(sin(Dist)*cos(PublLat)));
     
L0(0):=ROUND(6371*π/180*Dist,-3)+" km  "+ROUND(θ,0)+"°";
    
END;
   
END;
  
END;

  
//increment LoopIdx
  
LoopIdx(s):=LoopIdx(s)+1;
  FOR 
n FROM s DOWNTO 1 DO
    IF 
LoopIdx(n)>L4(nTHEN
      LoopIdx
(n):=L3(n);
      
LoopIdx(n-1):= LoopIdx(n-1)+1;
      IF 
n==2 THEN
       
PRINT(); 
       PRINT(
"



                              Completed: "
+ROUND(100*(1+LoopIdx(1)-L3(1))/(1+L4(1)-L3(1)),0)+" %");
      
END;
    
END;
  
END;
END;
END

It is working with the test case you provided.
I'm not a geocacher but I know some people who are and may be interested by your program.

Here are the detailed modifications I've made to your program:
  • added some local variables : n, Idx, LoopIdx, s
  • initialized LoopIdx to L3 : list of the start values, and s to the size of L3
  • replaced the nested FOR loops by a single one from 1 to the total of loops to be done: product of differences between upper and lower values in L4 and L3
  • modified the expression in the first loop to replace Loopi by LoopIdx(i)
  • added the increment of the LoopIdx values at the end of the FOR loop, including the progress PRINT instruction



RE: (Recursive) nested loops and IFs? - chromos - 12-17-2015 08:20 PM

Thank you, Didier, you helped me very much.

PHP Code:
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9",L5)) THEN
  
[...]
END
1) Lines above works perfectly. I tried to understand them, but not much successfuly. ΠLIST is importatnt or it may be ∑LIST too? I know, I could try it myself. :-)

2) Nested loops: I didn't try your code yet, but I will. There is ΠLIST again so I should study its usability much more.

-----
Meanwhile I updated my program again and I replaced nested loops with strings executed via EXPR. Fortunately, code isn't unreadable (I moved lines within FOR-DO and END; into subroutine which helped).

Before:
PHP Code:
FOR Loop1 FROM L3(1TO L4(1) DO
 FOR 
Loop2 FROM L3(2TO L4(2) DO
  FOR 
Loop3 FROM L3(3TO L4(3) DO
   FOR 
Loop4 FROM L3(4TO L4(4) DO
    [...]
   
END;
  
END;
 
END;
 PRINT(); 
 PRINT(
"



                        Completed: "
+ROUND(100*(1+Loop1-L3(1))/(1+L4(1)-L3(1)),0)+" %");
END

After (I declared Loop1, ... , Loop20 for sufficient headroom):
PHP Code:
//nested loops preparation
TempFor:="";
TempEnd:="";
TempBody:="";
FOR 
Loop FROM 2 TO SIZE(L2) DO
 
TempFor:=TempFor+"FOR Loop"+STRING(Loop)+" FROM L3("+STRING(Loop)+") TO L4("+STRING(Loop)+") DO ";
 
TempEnd:=TempEnd+"END; ";
END;
TempBody:="SUBRVALIDCOORDS();";
//end of preparation
FOR Loop1 FROM L3(1TO L4(1) DO
 
EXPR(TempFor+TempBody+TempEnd);
 PRINT(); 
 PRINT(
"



                        Completed: "
+ROUND(100*(1+Loop1-L3(1))/(1+L4(1)-L3(1)),0)+" %");
END
Maybe it isn't elegant solution, but at least I know what I'm doing.

I found interesting feature (or is it bug?): list variable cannot be used as FOR-DO counter (which is a pity).

Example:
PHP Code:
LoopList:=MAKELIST(0,X,1,15);
PRINT(
LoopList); // → {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
FOR LoopList(1FROM L3(1TO L4(1) DO
  PRINT(
LoopList); // → 0 (and program stops.)
END

----
It seems the program works now with any number of inequalities and with number of variables up to 20 which is more than enough. I will test it on more caches before uploading.

Thank you again very much, Didier.


RE: (Recursive) nested loops and IFs? - Didier Lachieze - 12-18-2015 08:06 AM

(12-17-2015 08:20 PM)chromos Wrote:  
PHP Code:
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9",L5)) THEN
  
[...]
END
1) Lines above works perfectly. I tried to understand them, but not much successfully. ΠLIST is important or it may be ∑LIST too? I know, I could try it myself. :-)

In this case you have to use ΠLIST: ΠLIST(list) returns the product of the list elements which is the equivalent of a Boolean AND while ∑LIST(list) returns the sum of the list elements which is the equivalent of a Boolean OR.

Nested IF conditions can be replaced by ANDs:

PHP Code:
IF (EXPR(L5(1))>=AND EXPR(L5(1))<=9THEN
  
IF (EXPR(L5(2))>=AND EXPR(L5(2))<=9THEN
    
IF (EXPR(L5(3))>=AND EXPR(L5(3))<=9THEN 

is the same as:

PHP Code:
IF (EXPR(L5(1))>=AND EXPR(L5(1))<=9) AND (EXPR(L5(2))>=AND EXPR(L5(2))<=9) AND (EXPR(L5(3))>=AND EXPR(L5(3))<=9THEN 

EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9",L5) returns a list with the result of the test for each element of L5, either 0 (false) or 1 (true).
Then ΠLIST returns the product (AND) of all these results: 0 (false) if at least one is false and 1 (true) if all are true.
As we work with lists this is not tied to the number of variables.

(12-17-2015 08:20 PM)chromos Wrote:  2) Nested loops: I didn't try your code yet, but I will. There is ΠLIST again so I should study its usability much more.

Here L4-L3 returns a list of the differences between the elements of L4 and L3, so ΠLIST(L4-L3) returns the product of these differences which gives the total number of loops to do.


RE: (Recursive) nested loops and IFs? - chromos - 12-18-2015 10:25 PM

This...
(12-18-2015 08:06 AM)Didier Lachieze Wrote:  ... ΠLIST(list) returns the product of the list elements which is the equivalent of a Boolean AND...
... and this...
Quote:... As we work with lists this is not tied to the number of variables...
... is explanation I needed. Thank you.

----

I updated Geo Coords Solver again, most visible thing is better workflow.

On this link is czech geocache -you can use e.g. google translator, so you can try to solve it. :-) (Hint - closest coordinates are usually the right ones).

[attachment=2988]


RE: (Recursive) nested loops and IFs? - Didier Lachieze - 12-18-2015 10:40 PM

One more thing :
PHP Code:
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9",L5)) THEN
  
[...]
END

can be replaced by :
PHP Code:
IF ΠLIST(EXPR(L5+">=0") AND EXPR(L5+"<=9")) THEN
  
[...]
END



RE: (Recursive) nested loops and IFs? - chromos - 12-18-2015 11:32 PM

I had unhandled A/B type expressions, so I modified your previous code into...
PHP Code:
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9 AND FP(EXPR(&1))==0",L5)) THEN 
... and it works.
In your new code...
PHP Code:
IF ΠLIST(EXPR(L5+">=0") AND EXPR(L5+"<=9") AND EXPR(FP(L5)+"==0")) THEN 
... it doesn't work. Your unmodified code works.


RE: (Recursive) nested loops and IFs? - Didier Lachieze - 12-19-2015 12:00 AM

(12-18-2015 11:32 PM)chromos Wrote:  In your new code...
PHP Code:
IF ΠLIST(EXPR(L5+">=0") AND EXPR(L5+"<=9") AND EXPR(FP(L5)+"==0")) THEN 
... it doesn't work. Your unmodified code works.

L5 is a list of strings, not a list of reals so FP(L5) doesn't work.
This should work but it starts to look a bit ugly:
PHP Code:
IF ΠLIST(EXPR(L5+">=0") AND EXPR(L5+"<=9") AND EXPR("FP("+L5+")==0")) THEN 



RE: (Recursive) nested loops and IFs? - chromos - 12-19-2015 12:05 AM

You're right. I'm too tired from it probably. :-)


RE: (Recursive) nested loops and IFs? - chromos - 01-17-2017 11:46 AM

Does anybody know why this stopped working in latest Prime firmware?
(in L5 are stringed expressions, something like "(A+B)").

PHP Code:
IF ΠLIST(EXPR(L5+">=0") AND EXPR(L5+"<=9") AND EXPR("FP("+L5+")==0")) THEN 

I replaced it with:

PHP Code:
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9 AND FP(EXPR(&1))==0",L5)) THEN 
... and this works, so I don't need another solution. I'm just curious why former code no longer works.