Post Reply 
Example of MISO solver for WP 34s
05-22-2018, 09:29 AM (This post was last modified: 05-22-2018 10:06 AM by gomefun2.)
Post: #1
Example of MISO solver for WP 34s
I will show an example of how to program a MISO (multiple input single output) solver mapped to a single button press for an equation. This is a MISO solver meaning that each time the program is run a different variable can be solved for, without having to rewrite the equation. This program will have named variables.

The equation the program will solve is Darcy's equation for Steady-State Flow. This is equation 6.4 on page 6.3 at http://infohost.nmt.edu/~petro/faculty/E...idflow.pdf

This is a 10 variable equation, with a worked example (at the link) so you can test the code to see if it worked for you.

70 LINES (71 LINES including the final END)

(NOTE: I use // for commenting the code)

LBL A //using this label assigns the program to the physical 'A button' on the calculator
CLα // clears the alpha registry
1 // puts 1 in the x registry
STO 00 // stores 1 into R00. R00's only purpose is to act as a pointer to the memory location. storing 1 into R00 means that R00 will point to the registry R01 (see below for example).
α's' // alpha's' puts s into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'Pe' // alpha'Pe' puts Pe into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'Pwf' // alpha'Pwf' puts Pwf into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'q' // alpha'q' puts q into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'Bo' // alpha'Bo' puts Bo into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'u' // alpha'u' puts u into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'k' // alpha'k' puts k into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'h' // alpha'h' puts h into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α're' // alpha're' puts re into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
α'rw' // alpha'rw' puts rw into the alpha registry
XEQ'VAR' // calls and executes the code at LBL'VAR'
RCL 99 // This recalls the location of output variable in memory (see the subfunctions below)
STO 00 // This stores the location from R99 into R00
SLV'SSR' // This solves function at LBL'SSR' (steady-state radial)
RTN // End of Main Function

LBL 'SSR' // This is where the Equation is stored
STO->00 // This stores whatever is in the X register to the location that is stored in R00. For example, if R00 contains 2, then the X register is stored to R02. The STO-> is different than STO (-> is for memory address location)
// STO->00 has no impact on the equation. The reason it is used is that it tells the calculator which variable to solve for. Whichever variable appears first after LBL'SSR' is the variable the calculator will solve for. By storing 5 into R00, and calling STO->00 as the first line in the equation, the calculator will store a random number into R05. But since R05 appears first the calculator will also solve for this registry as the unknown. It basically tricks the calculator to solving for any variable in the equation.
RCL 07 // recall k
RCL 08 // recall h
* // multiply them
RCL 02 // recall Pe
RCL 03 // recall Pwf
- // subtract them
* // multiply
#002 // # is for small integers (0-255) this will put the number 2 into the x registry
SDR 001 // shifts the decimal place once to the right turn 2 into 0.2
#141 // puts 141 into the x registry
+ // adds 0.2 and 141 to make 141.2 (the constant in the equation)
RCL 06 // u
* // multiply
RCL 05 // Bo
* // multiply
RCL 09 // re
RCL 10 // rw
/ // divide
LN // natural logarithm
RCL 01 // s
+ // addition
* // multiply
/ // divide
RCL 04 // q
- // subtract (for the solver to work the equation must be equal to zero (f(x) = 0), so I subtracted q from both sides)
RTN // End of the equation sub-function

LBL'VAR' // The purpose of this subfunction is to help save space when storing data to registers (these are repetive steps).
α'?' // alpha'?' adds a question mark to alpha register, this just makes the prompt look nicer
RCL->00 // the -> means this is an address recall. So this line recalls the value stored in the register at the location stored in R00. For example if R00 contains 3, the value stored in R03 is recalled. The purpose of this is to show the user what is currently stored in each variable.
PROMPT // This waits for user input (when running the program, key in a number and push R/S to enter the value)
STO->00 // Similar to RCL->00 above the -> tells the calculator to store the value in the x register to the location stored in R00.
x<0? // this is a test to see if the user input a negative number. The reason this is here is that all the numbers (aside from 's' in the equation must be positive. If a number is an input as negative then this tells the calculator to solve for that variable. It is just a way I decided to trick the calculator to solve for the correct variable. Since S can be negative I put it first, therefore the calculator will only solve for s (even if it is negative) only if all other variables are positive). x<0? is a conditional statement, if true, it will execute the next line of code, if false it will skip the next line of code.
XEQ'UNK' // this line executes only if the user puts a negative number in for the current variable. This function stores which variable is the one that should be solved for.
INC 00 // this increments R00, this puts a new value into R00, and since R00 is being used as the address locations in the memory this will increment the memory location to the next location. For example, if the program just stored a value into R02, this will increment the program so that the next iteration of the program will store a value into R03.
CLα // Clears the alpha registry
RTN // Ends the subfunction returns to the entry point in the main function

LBL'UNK' // This subfunction stores into memory the variable that should be solved for.
RCL 00 // Recalls the memory location stored in R00
STO 99 // Stores the location to R99. Since s is the first variable in the code, even if it is negative, the next iteration with a negative number (the one that actually wants to be solved for) will store its value here overtop the location of s. (s is the only number that could naturally be negative). s is only solved for if it is the only negative number.
RTN // ends the subfunction
END // Final End

This code could probably be modified slightly to make a general purpose MISO solver. I might end up writing that code next.

At any rate if anyone has a better way to do this code please let me know. I hope this helps at least one other person because it took me a while to figure this out. Thanks to Dieter on the forum for helping, and also the WP 34s manual.

(NOTE: if it isn't clear from the code, the calculator solves for the variable whose initial guess is negative, since these variables are not naturally negative. That is how it decides).
Find all posts by this user
Quote this message in a reply
05-22-2018, 05:40 PM (This post was last modified: 05-22-2018 05:41 PM by Dieter.)
Post: #2
RE: Example of MISO solver for WP 34s
(05-22-2018 09:29 AM)gomefun2 Wrote:  I will show an example of how to program a MISO (multiple input single output) solver mapped to a single button press for an equation.

I'll be glad to look at the program and see how it can be improved, but...
sorry, in my humble opinion this is completely unreadable.

There is no need to comment each and every line. If there is a line with a "+" it is not required to explain this is an addition, or if there is a "1" noone needs to know that this puts a "1" into X. This is obvious, so please comment only the essential things. For instance you could add the equation that is solved here.

Maybe you can provide a new listing, completely uncommented, and with a fixed-width font. Try the "code" box in the message editor. Maybe you can also add line numbers so that everyone who wants to comment on a specific piece of code can do so by referring to the respective line number. Here's a tip: type the program in Excel, add the line numbers in the column left of the code and then copy the result.

I hope you do not mind these suggestions, but the way it is now the program is extremely hard to oversee and understand. The pure listing – along with a few explanations after (!) the code – would be very helpful.

Edit: Ok, Ok, I did it myself:

Code:
001  LBL A
002  CLα
003  1
004  STO 00
005  α's'
006  XEQ'VAR'
007  α'Pe'
008  XEQ'VAR'
009  α'Pwf'
010  XEQ'VAR'
011  α'q'
012  XEQ'VAR'
013  α'Bo'
014  XEQ'VAR'
015  α'u'
016  XEQ'VAR'
017  α'k'
018  XEQ'VAR'
019  α'h'
020  XEQ'VAR'
021  α're'
022  XEQ'VAR'
023  α'rw'
024  XEQ'VAR'
025  RCL 99
026  STO 00
027  SLV'SSR'
028  RTN
029  LBL 'SSR'
030  STO->00
031  RCL 07
032  RCL 08
033  *
034  RCL 02
035  RCL 03
036  -
037  *
038  #002
039  SDR 001
040  #141
041  +
042  RCL 06
043  *
044  RCL 05
045  *
046  RCL 09
047  RCL 10
048  /
049  LN
050  RCL 01
051  +
052  *
053  /
054  RCL 04
055  -
056  RTN
057  LBL'VAR'
058  α'?'
059  RCL->00
060  PROMPT
061  STO->00
062  x<0?
063  XEQ'UNK'
064  INC 00
065  CLα
066  RTN
067  LBL'UNK'
068  RCL 00
069  STO 99
070  RTN

By the way: SLV works as a test. If no solution is found the next line is skipped! This way you can add your own error handler.
And SLV expects two initial guesses in X and Y. How does your program handle this?

Dieter
Find all posts by this user
Quote this message in a reply
05-22-2018, 07:43 PM (This post was last modified: 05-22-2018 10:08 PM by Dieter.)
Post: #3
RE: Example of MISO solver for WP 34s
(05-22-2018 09:29 AM)gomefun2 Wrote:  I will show an example of how to program a MISO (multiple input single output) solver mapped to a single button press for an equation.
...
At any rate if anyone has a better way to do this code please let me know.

OK, here is my very first, almost untested version, so try it at your own risk ;-)

Code:
001 LBL A
002 CLα
003 # 001
004 STO J
005 CLx
006 STO K
007 α'S'
008 XEQ 99
009 α'Pe'
010 XEQ 99
011 α'Pwf'
012 XEQ 99
013 α'q'
014 XEQ 99
015 α'Bo'
016 XEQ 99
017 α'μ'
018 XEQ 99
019 α'k'
020 XEQ 99
021 α'h'
022 XEQ 99
023 α'Re'
024 XEQ 99
025 α'Rw'
026 XEQ 99
027 RCL K
028 x≥1?
029 GTO 00
030 CLα
031 α'Sel'
032 α'ect'
033 α' Va'
034 α'r !'
035 VIEWα
036 PSE 20
037 GTO A
038 LBL 00
039 STO J
040 # 1/2
041 # 200
042 SLV'SSR'
043 SKIP 001
044 ERR 20
045 RTN
046 LBL 99
047 α'=?'
048 RCL→J
049 PROMPT
050 STO→J
051 x≥0?
052 SKIP 002
053 RCL J
054 STO K
055 INC J
056 CLα
057 RTN
058 LBL'SSR'
059 STO→J
060 RCL 07
061 RCL× 08
062 RCL 02
063 RCL- 03
064 ×
065 # 002
066 SDR 001
067 # 141
068 +
069 RCL× 06
070 RCL× 05
071 RCL 09
072 RCL/ 10
073 LN
074 RCL+ 01
075 ×
076 /
077 RCL- 04
078 RTN

Some remarks:
  • Instead of R00 and R99 (who knows if R99 even exists?) the program uses the J and K registers which are always available. The variable to be solved is stored in K. It is initialized with zero to make sure the user has selected one of the variables as the one to solve for (cf. next point).
    Note: J and K are also used for the parameters of some statistical distributions. So if these are involved you should change J and K to, say, A and B. In this case be sure to start the program with a SSIZE4 command as A and B hold the upper (5th and 6th) stack levels in SSIZE8 mode.
  • The program checks if the user has selected a variable to solve for (cf. line 028). If not, a respective message is displayed and the input routine starts over.
  • Instead of LBL"VAR" the program uses LBL 99 for the input routine. That's much faster to enter. Don't know if this even saves some bytes.
  • I have renamed some variables. The 34s character set includes a µ (switch to lower case and press g(reek) M). Even subscripts are available (though not used here).
  • The clumsy UNK routine was removed completely. If the user has entered a non-negative variable the program simply skips over the two lines that store the index of the solver variable.
  • The implemented equation uses RCL-arithmetics which makes it shorter and more effective. Also the equation was moved to the end of the program.
  • If no root is found an error message appears (ERR 20). Yes, the 34s has a set of predefined messages (MSG) and errors (ERR) that are quite handy in such cases.
  • The solver needs two initial guesses in X and Y. Since the typical values for the variables may vary by some orders of magnitude I've simply set 0,5 and 200 (cf. line 040/041). This definitely is ..."sub-standard". Better ideas: ask the user for two guesses, or arrange the variables in two groups (say, typically less than 10 or more than 10) and derive a guess from the index of the variable to solve for.

    Edit: here's an even better idea. The user enters the solver variable with negative sign to indicate that this is the one to solve for. So simply have the user enter a (negative) guess for this variable. Then start the solver with half and twice that (absolute) value. Example: you want to solve for a variable that should be somewhere near 100. So enter –100 at the respective prompt and the solver will start with 50 and 200. Could this be a good idea? I tried it and it seems to work very well.

I tried the formula in the PDF and solved for q first (result: q=1120,966). Then I changed q to 1000 and solved for µ which was then returned as µ=0,6105.

So far for the moment. ;-)

Dieter
Find all posts by this user
Quote this message in a reply
05-23-2018, 05:47 PM (This post was last modified: 05-24-2018 02:35 PM by burkhard.)
Post: #4
RE: Example of MISO solver for WP 34s
I had a little fun keying this (the original version) in on my lunch break and figuring out the syntax to get some of the characters to appear. Fortunately I purchased the WP-34s manual :-)

A couple of comments:
1. Nice job! Thanks for including the PDF ref with the example with numbers given. That made a nice check that everything went in OK. I'd like to see more programs that demonstrate the ropes of WP34s programming capability. It is really a pretty handy *small* calculator.
2. I had heard the acronym MISO before, but didn't know the meaning. I understand now and can appreciate the usefulness of being able to solve for any one of the variables. I also like that it can be run repeatedly in sequence, each time retaining the prior inputs as defaults.
3. Your using a negative number as a flag to mean ""Solve for me!" was clever and sensible for this specific example. One can't get away with that always, though...
4. While I agree with Dieter that one doesn't need to comment a simple addition operation, a lot of the comments within "VAR" and "SSR" subroutines were pretty useful and appreciated. Perhaps they aren't needed for an experienced master of keystroke programming, but they were helpful to me. Completely stripping them all out would be a loss. Maybe put them below the code as footnotes by step number so they can be referenced only if needed?
5. Monospaced font was a lot easier to read :-)

Thanks again!
Find all posts by this user
Quote this message in a reply
05-23-2018, 07:36 PM
Post: #5
RE: Example of MISO solver for WP 34s
(05-23-2018 05:47 PM)burkhard Wrote:  3. Your using a negative number as a flag to mean ""Solve for me!" was clever and sensible for this specific example. One can't get away with that always, though...

I just noticed that even in the given example equation one of the variables (S) may be negative. So there has to be a workaround. The original program prompts for S as the first variable, and when the solver starts it does not check if a negative value has been entered (instead it solves for S). This is a possible solution for this particular case. My program version (which checks if the user has selected a variable) can not handle negative S values. It assumes that all data is non-negative.

So there should be a better solution for flagging the variable to solve for. I have been thinking about several methods, but none is really convincing. Maybe someone has a better idea?

Dieter
Find all posts by this user
Quote this message in a reply
05-23-2018, 09:57 PM
Post: #6
RE: Example of MISO solver for WP 34s
I will take a look at these suggestions, just super busy until the weekend this week. Thanks.
Find all posts by this user
Quote this message in a reply
05-24-2018, 06:17 PM (This post was last modified: 05-24-2018 06:59 PM by Dieter.)
Post: #7
RE: Example of MISO solver for WP 34s
(05-23-2018 07:36 PM)Dieter Wrote:  So there should be a better solution for flagging the variable to solve for. I have been thinking about several methods, but none is really convincing. Maybe someone has a better idea?

If the input can be essentially ...anything, there are two basic methods:

- At the input prompt, press a key like B or C to continue at a different position in the program. This sounds nice ("simply press B at the input prompt when this is the variable you want to solve for"), but it will not work here as it pops the return stack. So the next RTN will not return from the pending subroutine call (LBL 99 or "VAR") to continue with the next variable input, instead the program will simply stop. However, this can be fixed by changing the XEQ calls into GTOs and then jump back to the next variable input with a GTO→J. Of course this requires ten additional labels 01...10. If you want to give it a try, here is the code. Press B when the variable to solve for shows up.

Code:
001 LBL A
002 CLx
003 STO J
004 STO K
005 CLα
006 α'S'
007 GTO 99
008 LBL 01
009 α'Pe'
010 GTO 99
011 LBL 02
012 α'Pwf'
013 GTO 99
014 LBL 03
015 α'q'
016 GTO 99
017 LBL 04
018 α'Bo'
019 GTO 99
020 LBL 05
021 α'μ'
022 GTO 99
023 LBL 06
024 α'k'
025 GTO 99
026 LBL 07
027 α'h'
028 GTO 99
029 LBL 08
030 α'Re'
031 GTO 99
032 LBL 09
033 α'Rw'
034 GTO 99
035 LBL 10
036 RCL K
037 x≥1?
038 GTO 00
039 CLα
040 α'Sel'
041 α'ect'
042 α' Va'
043 α'r !'
044 VIEWα
045 PSE 20
046 GTO A
047 LBL 00
048 STO J
049 # 1/2
050 RCL×→J
051 # 002
052 RCL×→J
053 SLV'SSR'
054 SKIP 001
055 ERR 20
056 RTN
057 LBL 99
058 INC J
059 α'=?'
060 RCL→J
061 PROMPT
062 SKIP 004
063 LBL B
064 RCL J
065 STO K
066 R↓
067 STO→J
068 CLα
069 GTO→J
070 LBL'SSR'
071 STO→J
072 RCL 07
073 RCL× 08
074 RCL 02
075 RCL- 03
076 ×
077 # 002
078 SDR 001
079 # 141
080 +
081 RCL× 06
082 RCL× 05
083 RCL 09
084 RCL/ 10
085 LN
086 RCL+ 01
087 ×
088 /
089 RCL- 04
090 RTN

- Use a flag. That's what the next version does. Here the program expects the user to set flag A when the prompt for the variable to solve for appears (press SF A). This turns on the big "=" sign in the display, so there is a visual feedback.

Here is the code:

Code:
001 LBL A
002 CLx
003 STO J
004 STO K
005 CLα
006 α'S'
007 XEQ 99
008 α'Pe'
009 XEQ 99
010 α'Pwf'
011 XEQ 99
012 α'q'
013 XEQ 99
014 α'Bo'
015 XEQ 99
016 α'μ'
017 XEQ 99
018 α'k'
019 XEQ 99
020 α'h'
021 XEQ 99
022 α'Re'
023 XEQ 99
024 α'Rw'
025 XEQ 99
026 RCL K
027 x≥1?
028 GTO 00
029 CLα
030 α'Sel'
031 α'ect'
032 α' Va'
033 α'r !'
034 VIEWα
035 PSE 20
036 GTO A
037 LBL 00
038 STO J
039 # 1/2
040 RCL×→J
041 # 002
042 RCL×→J
043 SLV'SSR'
044 SKIP 001
045 ERR 20
046 RTN
047 LBL 99
048 INC J
049 CF A
050 α'=?'
051 RCL→J
052 PROMPT
053 STO→J
054 RCL J
055 FS?C A
056 STO K
057 CLα
058 RTN
059 LBL'SSR'
060 STO→J
061 RCL 07
062 RCL× 08
063 RCL 02
064 RCL- 03
065 ×
066 # 002
067 SDR 001
068 # 141
069 +
070 RCL× 06
071 RCL× 05
072 RCL 09
073 RCL/ 10
074 LN
075 RCL+ 01
076 ×
077 /
078 RCL- 04
079 RTN

In both cases the program also takes the input at this prompt as an estimate for the solution. It feeds 1/2x and 2x this value as the two initial guesses into the solver. So if you enter 100 the first two guesses are 50 and 200. Adjust this as you like with the two factors in line 049/051 or 039/041, respectively.

Now try it and see if this works for you. ;-)

Dieter
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 1 Guest(s)