HP Forums
List Commands Library for 50g - Printable Version

+- HP Forums (https://www.hpmuseum.org/forum)
+-- Forum: HP Calculators (and very old HP Computers) (/forum-3.html)
+--- Forum: General Forum (/forum-4.html)
+--- Thread: List Commands Library for 50g (/thread-8555.html)

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21


RE: List Commands Library for 50g - pier4r - 07-22-2018 10:14 AM

(07-21-2018 11:12 PM)Valentin Albillo Wrote:  This is not the first time this happens to one of my posts lately but I sure expect it will be the last on your part.
That's a tad aggressive :/ .

I give it to you that I didn't quote it directly, rather I recalled what I remember from your post from my memory, that of course can be different from you wrote. From now on I will add "what my memory remembers from X", that cannot be disputed as it is really in that way..

And yes the quote was different.
Quote:That's the decades-long problem I've always resented: people will constantly produce this or that library, or this or that utilities ROM, or this or that utilities LEX files and so on and so forth, which are then published and/or made available for free or nearly so, intended to be used in people's own programs and such. So far so good.

Regrettably, most people either don't use them in actual, non-trivial programs or, if they do, they don't make them publicly available so in the end the community rarely gets full-fledged, useful programs but tons upon tons of routines, libraries, utilities, etc., apparently because people love to write libraries and utilities (it's like solving a puzzle or a challenge) but complex, useful programs not so much.
http://www.hpmuseum.org/forum/thread-10967-post-99989.html#pid99989


RE: List Commands Library for 50g - DavidM - 07-23-2018 02:26 AM

(07-21-2018 09:23 PM)rprosperi Wrote:  Although I can't foresee any real requirement for me to ever need to install this library, I have followed it's birth and growth closely as it has evolved, as the discussions about implementation choices, test cases used and proposed by readers and even your own reassessing and changing things is very educational for even basic RPL programmers, like me.

I continually find that the best ideas are usually in other people's heads, so I know what you mean. Smile

(07-21-2018 09:23 PM)rprosperi Wrote:  Also, the ensuing discussions about using lists for various things has led to additional interest in exploring some of those areas as well.

I started down the RPL path when I was forced to sell my 41C kit in order to acquire the 48sx back in '92 (which I still have and sometimes use, thanks in part to your referral to Adam). Although I had always wanted to start digging into the list features, by the time I acquired my 49g+ I was focusing mostly on SysRPL coding and thus didn't have quite as much "list abstraction" available with that command set. So it wasn't until recently that I started trying to dig into those tools. The more I used them, the more I realized that there were some obvious omissions from the standard catalog that would be good to add, hence the library. Feature creep settled in, of course, and now there's lots of goodies added to the mix.

Some of the string commands are also very useful independent of any list connections. I've occasionally thought it might be handy to take some of those commands and port them over for use with the older 48's, which I may still do.

(07-21-2018 09:23 PM)rprosperi Wrote:  So you can't really judge such a tool's contribution solely by the number of users that have installed it, it has other positive influences just from being discussed.

...and that makes this all worthwhile, perhaps even to folks that don't care to spend any time with RPL. Some of the discussions that came from the shuffling approach(es) and testing would seemingly have value regardless of platform. And many of the specific command discussions could just as easily pertain to other platforms that support lists, such as the Prime. Hopefully others have seen the same potential for crossover.

Thanks for keeping an open mind and participating, Bob. I believe that's what ultimately defines the value of any open discussion in any forum -- cross-pollination of ideas that spark even greater ideas.


RE: List Commands Library for 50g - brickviking - 07-26-2018 05:00 AM

I had a couple of questions vaguely related to ListExt.
  • Aside from the speed of the 41C platform, what else would preclude it from some of the list-processing aspects present in ListEx?
  • Has a list-processing plugin/mod/ROM been created for that platform, and if so, how useful has it been?
  • If one hasn't been created yet (like, huh??), how much work would be required to include a reasonable subset of ListExt features in a new MCode project?

I haven't had any experience with the 41C family, so I can't comment on how fast/slow it is in comparison to other families such as the 48xX family. I like the fact that a library like this can be preloaded if you're going to use it a lot, or left out if you don't need it much.

(Post 262)


RE: List Commands Library for 50g - pier4r - 07-26-2018 12:38 PM

(07-23-2018 02:26 AM)DavidM Wrote:  I believe that's what ultimately defines the value of any open discussion in any forum -- cross-pollination of ideas that spark even greater ideas.

That's a nice sentence.


RE: List Commands Library for 50g - DavidM - 07-26-2018 04:39 PM

(07-26-2018 05:00 AM)brickviking Wrote:  I had a couple of questions vaguely related to ListExt.
  • Aside from the speed of the 41C platform, what else would preclude it from some of the list-processing aspects present in ListEx?
  • Has a list-processing plugin/mod/ROM been created for that platform, and if so, how useful has it been?
  • If one hasn't been created yet (like, huh??), how much work would be required to include a reasonable subset of ListExt features in a new MCode project?

I haven't had any experience with the 41C family, so I can't comment on how fast/slow it is in comparison to other families such as the 48xX family. I like the fact that a library like this can be preloaded if you're going to use it a lot, or left out if you don't need it much.

(Post 262)

Although I once owned a 41C bundle (and used it daily), I had to sell it back in the early 90s and thus haven't kept up-to-date with that part of the calculator world. So these questions are probably best suited for others that are more current on that platform. Hopefully some of the more knowledgeable folks will see this and respond.

That said, the first thing that strikes me about "list processing" in a 41 environment is that the concept of varying object types is mostly limited to strings and numbers, and even those are fairly narrowly defined. Since a "list of numbers" isn't much different than a vector or matrix, you'd probably find the lion's share of programs being described as using arrays, matrices, or vectors instead of lists. Even dealing with those 41 data types is mostly handled through a layer of abstraction, with the actual data being stored in a series of registers with meta information (location, size, type) stored separately in some conventional way.

So the context on the 41 would probably be limited to numeric arrays, and I'm sure lots of functionality exists for that already. It's probably not described as "list processing", though.

This really isn't my area of expertise, though, so I should probably just stop typing now and leave it to those more familiar with the 41 than me. Smile


RE: List Commands Library for 50g - DavidM - 07-27-2018 09:01 PM

An Illustrative Example

Consider how you might implement the following problem:

Create an RPL program to convert a non-negative integer into a string representing that number in a base ranging from 2 to 36.


In order to stay focused on the general solution, I'm going to skip range checks and any consideration of exact-vs-approximate numbers here. One such implementation of the above, then, might be as follows:

Code:
Program: n2b
\<<
  "" ROT                   @ move result string into position
  DO                       @ main loop
    PICK3                    @ make a copy of given base
    IDIV2                    @ determine quotient, remainder
    DUP 9 > 55 48 IFTE       @ convert remainder to corresponding base character
    + CHR
    ROT + SWAP               @ add new character to front of result
  UNTIL                    @ do main loop until number is fully processed
    DUP NOT
  END
  DROP NIP                 @ drop supplemental stack variables
\>>

I believe this to be a good example of the type of problem that translates fairly well to a list-focused approach. It also happens to utilize functionality which has good representation in the ListExt library. So how might this be done using ListExt features? There's 3 commands in particular that will work nicely here. They are:

I→BL (Integer to Base List): converts an integer into a list of remainders after repeated division by a constant
NL→S (Number List to String): converts a list of character numbers into a string
CHR+ (Character Offset): adds an offset to the CHR value of each character of a string

Using the above commands, the n2b program could be re-written very simply as
Code:
Program: n2bLE
\<<
  I\->BL                   @ convert number and base into a list of remainders
  NL\->S                   @ convert the remainder list into a string
  { 0 9 48 } CHR+          @ replace characters in range 0..9 with 48..57
  { 10 35 55 } CHR+        @ replace characters in range 10..35 with 65..90
\>>

If we run either of the above programs with the following on the stack
Code:
2: 123456789012
1: 36

...the result is the same: "1KPQZG2C".

Looking at the ListExt version more closely, we see the following occur at each step (note that there are no loops in the UserRPL code):

Code:
STEP                       STACK
-------------------------  ----------------------------
(pre-launch)               2: 123456789012
                           1: 36
                                        
I→BL                       1: { 1 20 25 26 35 16 2 12 }

NL→S                       1: "▪▪▪▪#▪▪▪"

{ 0 9 48 } CHR+            1: "1▪▪▪#▪2▪"

{ 10 35 55 } CHR+          1: "1KPQZG2C"


Code Size

The size of the compiled code is a frequent concern of programmers, so let's consider that aspect for the above two programs. The following assumes that both programs were entered with the calculator in Exact mode. Changes to the mode before editing may alter the compiled size of the code objects.

Size
n2b: 78.5 bytes
n2bLE: 73 bytes

The similarity in size may come as a surprise when looking at the actual source code. Despite its relatively smaller footprint in text form, the ListExt version is encumbered by the following when compared to the first program:
- library calls consume 5.5 bytes of storage when compiled, compared with 2.5 bytes for most built-in commands
- the lists consume 16.5 and 24.5 bytes of storage for a combined total of 41 bytes (a little over half of the total byte count in that version)

The lesson here: delineated lists in source code can take up a lot of space, so it's best to encode them as functions of other commands (when possible) if space is a concern. There's several commands in the CREAT submenu that can help with this, mostly for sequences and repetitive sets.


Performance

This is a good example to discuss some performance considerations, as it shows what I consider to be a typical set of characteristics for programs that make use of ListExt functions.

Speed of Execution
n2b: 0.723s
n2bLE: 0.114s

While this shows a decent advantage for the ListExt version, the results in practice can vary depending on many factors. For one thing, someone concerned about performance should never use the IDIV2 command. Replacing that single command with the much longer sequence "DUP2 MOD ROT OVER - ROT / SWAP" will actually speed up the program (0.668s). That may seem counterintuitive, but IDIV2 really is that slow. Additionally, Exact and Approximate mode results will differ. These timings were observed in Exact mode.

Another consideration is that anything that can reduce the quantity and size of loops in the UserRPL code will have a noticeable impact on performance. In this particular example, converting a number to a base that results in only a single character will actually run faster than the ListExt version. In that situation, the main loop code is executed only once. As soon as the result string needs more than one character, though, the ListExt version is faster.

This helps to illustrate a fundamental concept of list processing on RPL calculators: performance gains are more pronounced as the size of the input and output grows. There is an overhead required to deal with lists for all commands (whether built-in or ListExt), and if the data sets are small, this overhead may actually negate any potential performance gain over processing the data without lists. As the data sets grow in size, that overhead is surpassed by the gains made from using faster internal looping structures and optimized code in the list commands.

So if you know in advance that data sets will be small, it may be best to avoid the use of lists. Conversely, knowing that there will be larger data sets makes it highly likely that coding with lists will improve performance (sometimes substantially). Many of the ListExt commands have critical sections implemented in Saturn assembly code, which gives them a sizable speed advantage over similar UserRPL implementations.


Summary

Like any programming paradigm, list processing has its advantages and disadvantages. In situations where it is a good fit, the programmer has the opportunity to focus on simpler steps to achieve the desired goal. Creating and maintaining lists carries with it some overhead which may negatively offset performance when lists are small. These offsets are mitigated, however, as list sizes grow. Depending on the needed functionality and data set sizes, list processing may actually grant significant performance gains.


RE: List Commands Library for 50g - DavidM - 07-30-2018 06:19 PM

More list/string examples

One of my earliest "real" jobs was working at a retail establishment that occasionally sold items that had to be special-ordered. This was a relatively small operation back in the early 80s that didn't have a lot of automation in their POS (point of sale) equipment. In an effort to track the cost information through the sales process, they placed price stickers on these special-ordered items that actually had the internal cost information coded on them with a simple substitution cipher (the digits of the cost were substituted with letters from a predetermined code). It wasn't sophisticated, but it worked for them.

As an example, I'll use the word "LOGARITHMS" to represent the digits 0-9 to encode some values to show how simple this actually was (the decimal point was implied):

LOGARITHMS
0123456789


123.45 => "OGARI"
99.99 => "SSSS"
10.89 => "OLMS"

There's several ways I can think of using standard UserRPL commands to program an encoding algorithm like this. Most involve POS, SUB, SREPL and/or related commands in some kind of loop to convert the numbers into a string containing the substituted characters. A few of the ListExt commands can make this simpler, though. The following shows one such method:

Code:
PROGRAM                             STACK DATA
---------------------------------   ---------------------------------------
                                    1: 10.89
«
  "LOGARITHMS" S→SL SWAP            2: { "L" "O" "G" "A" "R" "I" "T" "H" "M" "S" }
                                    1: 10.89

  1E2 * I→NL 1. ADD                 2: { "L" "O" "G" "A" "R" "I" "T" "H" "M" "S" }
                                    1: { 2. 1. 9. 10. }

  LPICK                             1: { "O" "L" "M" "S" }

  SL→S                              1: "OLMS"
»


The reverse of the above process is also relatively simple:

Code:
PROGRAM                             STACK DATA
---------------------------------   ---------------------------------------
                                    1: "OLMS"
«
  "LOGARITHMS" SWAP                 2: "LOGARITHMS"
                                    1: "OLMS"

  S→SL                              2: "LOGARITHMS"
                                    1: { "O" "L" "M" "S" }

  POS                               1: { 2. 1. 9. 10. }

  1. -                              1: { 1. 0. 8. 9. }

  NL→I 1E2 /                        1: 10.89
»

I recall suggesting to the owners that they could accomplish a similar goal with even fewer letters needed on the stickers (and better protection of the info) if they just used a longer code word and converted the cost to a new base which used those letters as the digits. The individual who administered the custom order process gave me the evil eye when she realized that doing so would require more than a simple look at a table to decode the values. Suffice it to say that they never went for it... but you could! The previous post in this thread gives some hints to some handy ListExt commands that would help.

Short descriptions of the ListExt commands used above:

S→SL: converts a string to a list of characters
SL→S: converts a list of characters to a string
I→NL: converts an integer to a list of numbers
NL→I: converts a list of numbers to an integer
LPICK: returns a list containing identified elements in specified order


RE: List Commands Library for 50g - John Keith - 07-30-2018 07:28 PM

Neat examples, David!

Those substitution codes were used well into the 90's, even by large retailers. IIRC, the most common code words were CHARLESTON and BRUSHCLEAN. Knowing the code, one could often see quite eyebrow-raising markups!

John


RE: List Commands Library for 50g - math7 - 07-30-2018 07:34 PM

Can these functions be ported for the processing of lists to the HP Prime? Could you place the source code?


RE: List Commands Library for 50g - DavidM - 07-30-2018 07:43 PM

(07-30-2018 07:34 PM)math7 Wrote:  Can these functions be ported for the processing of lists to the HP Prime? Could you place the source code?

I don't own a Prime, and haven't spent enough time with an emulated one to be of much help there. But I believe someone else has already created a set of list commands for the Prime -- perhaps StephenG1CMZ? I believe he's been working on it for a while, and from what I recall he had some similar functionality in it.


RE: List Commands Library for 50g - Didier Lachieze - 07-30-2018 08:16 PM

On the HP Prime :

S→SL: converts a string to a list of characters => EXECON("CHAR(&1)",ASC(string))
SL→S: converts a list of characters to a string => ΣLIST(list)
I→NL: converts an integer to a list of numbers => ASC(STRING(integer,1))-48
NL→I: converts a list of numbers to an integer => EXPR(CHAR(list+48))
LPICK: returns a list containing identified elements in specified order =>
MAKELIST(list1(list2(I)),I,1,SIZE(list2))

For example :
Code:
list1:=EXECON("CHAR(&1)",ASC("LOGARITHMS"));      // list1:={"L","O","G","A","R","I","T","H","M","S"}
list2:=ASC(STRING(10.89*100,1))-47;               // list2:={2,1,9,10}
MAKELIST(list1(list2(I)),I,1,SIZE(list2));        // returns {"O","L","M","S"}
ΣLIST(MAKELIST(list1(list2(I)),I,1,SIZE(list2))); // returns "OLMS"



RE: List Commands Library for 50g - Thomas Klemm - 07-30-2018 08:37 PM

(07-30-2018 08:16 PM)Didier Lachieze Wrote:  
Code:

list2:=ASC(STRING(10.89*100))-47;                 // list2:={2,1,9,10}

Based on the definitions above that should be rather:
Code:

list2:=ASC(STRING(10.89*100))-48;                 // list2:={1,0,8,9}

Or is that on purpose?

Kind regards
Thomas


RE: List Commands Library for 50g - Didier Lachieze - 07-30-2018 08:42 PM

(07-30-2018 08:37 PM)Thomas Klemm Wrote:  Or is that on purpose?

It is on purpose, it is the equivalent of this line in the first program in the post #367 above:

Code:
1E2 * I→NL 1. ADD



RE: List Commands Library for 50g - Thomas Klemm - 07-30-2018 09:09 PM

Thanks for the clarification!


RE: List Commands Library for 50g - Didier Lachieze - 07-30-2018 09:44 PM

Note: I have updated my post above to replace ASC(STRING(integer))-48 by ASC(STRING(integer,1))-48.
This ensures it works for all number formats in the Home settings.


RE: List Commands Library for 50g - DavidM - 07-30-2018 10:26 PM

(07-30-2018 08:16 PM)Didier Lachieze Wrote:  SL→S: converts a list of characters to a string => ΣLIST(list)

This reminds me of another opportunity to reinforce a point I made in the previous post (the one about base conversions).

ΣLIST can be used on a 50g to accomplish the same goal. It's what I normally use for concatenating lists of strings in RPL code if any of the strings are longer than 1 character.

ΣLIST is a ROMPTR in RPL code, so it takes up the same 5.5 bytes that any library call does. No advantage there.

{ "A" "B" "C" "D" } ΣLIST returns a result in about .023s, and { "A" "B" "C" "D" } SL→S does the same thing in about .018s. SL→S is marginally faster for that list, but not anything to get excited about.

The real benefit comes as the input list grows larger. A list of 500 characters takes ΣLIST 1.521s, but that same list is completed by SL→S in .0385s. SL→S is more limiting in what it accepts as input (it only accepts a list of single characters), but the payoff for that limitation is enhanced performance. This is a common theme to many of the ListExt commands.


RE: List Commands Library for 50g - pier4r - 08-06-2018 05:59 PM

I don't know if what I am going to post belongs here or in the little explorations (n1). I post it here to raise the chance to get even more better commands. Read it as "I want commands that think for you!".

Let's expose the problem. Last week I played a cooperative board game, massive darkness. The game is not bad, although it may be too in favor of the players after level 3. The dice of the game, though, are not the common d6. They have elements that cannot be added to the others, therefore I wanted to know their distribution.

For example pick the Yellow dice for attacks. It has:
Blank
1 Sword
1 Sword
1 Sword
1 Sword
2 Swords / 1 Bam
(n3)


Of course I said "I can do it! Pen and paper and the sharp el506w and a bit of theory will not fail me". Of course they did not fail me, I failed myself once I tried to compute the distribution for 3 dice. Until 2 dice I got it right.

As usual when I fail I resort to automation to save my situation. Good math people solve everything on their paper sheets, poor ones use their calculators. That's my motto (n2), but hey at least I get an answer!

Thinking a bit how could I model quantities that cannot be added together, I ended up with a list of lists. So a yellow dice is modeled as follows
Code:

  {
    { 0 0 0 } @blank
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 2 1 0 } @2 swords 1 bam
  }

I was relatively happy thinking I could roll the two dice, add the results, and then use the awesome LRPCT . LRPCT: it gets a list in input and the result are two sublists. The first with the elements of the list in input, without duplicates (well, it is not exactly that, see below), and the second list with the occurrences of the elements of the first list in the input list.

But then I discovered it didn't work as the list in input should be sorted first, otherwise LRPCT doesn't achieve what I want.

So I tried SORT or LSORT on the result list, result list being something like the list describing the yellow dice.
Well both failed me (I also had no big expectations being my case an edge case), as for example the sublist { 2 1 0 } was sorted before { 2 0 0 } and then again {2 1 0} was listed.

Therefore I couldn't use LRPCT. I was in total despair.

What I did was a workaround. First getting the elements of the result list, without duplicates (it works), and then counting the occurrences of each element with LCNT (it works).
Below there is the code. The interesting part is at the end.

What I ask is: Could we have a LRPCT that does first LDDUP and then LCNT , to avoid sorting problems in the input list?

If I would have used vectors instead of sublist, would it have worked? (I didn't test)
Ok I tested, vectors are unsortable. Another point for a LRPCT where a LDDUP is done first and then LCNT.

Code:

  gvDiceSize
  6

  gvYellowDice
  {
    { 0 0 0 } @blank
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 2 1 0 } @2 swords 1 bam
  }

  gp2YellowArg
  \<<
  \>>

  gp2Yellow
  @worked 2018-08-06
  \<<
    {}  "lvResultList"       DROP
    {}  "lvResultListDDUP"   DROP
    
    {}  "lvFirstDiceRoll"   DROP
    
    \->
    lvResultList
    lvResultListDDUP
    
    lvFirstDiceRoll
    
    \<<
      1 gvDiceSize
      FOR lvPos1
      
        gvYellowDice
        lvPos1
        GET 'lvFirstDiceRoll' STO
        
        1 gvDiceSize
        FOR lvPos2
          gvYellowDice
          lvPos2
          GET
          
          lvFirstDiceRoll
          ADD @add the two lists
          
          lvResultList SWAP 
          LPSHR 'lvResultList' STO
            @add the result as sublist to the result list.
        NEXT
      NEXT
      
      lvResultList LDDUP @results without duplicates
      1
      \<<
        DUP @duplicate L1
        lvResultList SWAP @bring the single element on L1
        LCNT @count the value
        \->TAG @tag the element with its frequency 
      \>>
      DOSUBS
      
      @output:
      @results without duplicates and their frequency in a list
    \>>
  \>>


n1: http://www.hpmuseum.org/forum/thread-7955.html
n2: of course if the problem is large, then good ones use their calculators, poor ones use a beefy computer. And so on. The point being: some people are efficient the others use brute force, if their approach is correct at all.
n3: more here - https://www.reddit.com/r/MassiveDarkness/comments/6d1fqu/massive_darkness_dice_distributions/


RE: List Commands Library for 50g - StephenG1CMZ - 08-06-2018 08:37 PM

(07-30-2018 07:34 PM)math7 Wrote:  Can these functions be ported for the processing of lists to the HP Prime? Could you place the source code?

For the Prime, there is my List API.
Alternatively, Primer's Liblist may help.

Let me know if you want any additional functionality and I will try to find some time.


RE: List Commands Library for 50g - DavidM - 08-07-2018 01:47 PM

(08-06-2018 05:59 PM)pier4r Wrote:  I don't know if what I am going to post belongs here or in the little explorations (n1). I post it here to raise the chance to get even more better commands. Read it as "I want commands that think for you!".

Posting here seems perfectly reasonable, especially since you are focusing on the functionality of some specific ListExt commands.

(08-06-2018 05:59 PM)pier4r Wrote:  Thinking a bit how could I model quantities that cannot be added together, I ended up with a list of lists. So a yellow dice is modeled as follows
Code:

  {
    { 0 0 0 } @blank
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 1 0 0 } @1 sword
    { 2 1 0 } @2 swords 1 bam
  }

What's the purpose of the third element in the sublists? Is there a third potential item on each die (something other than a sword or "bam")?

(08-06-2018 05:59 PM)pier4r Wrote:  So I tried SORT or LSORT on the result list, result list being something like the list describing the yellow dice.
Well both failed me (I also had no big expectations being my case an edge case), as for example the sublist { 2 1 0 } was sorted before { 2 0 0 } and then again {2 1 0} was listed.

As far as I'm aware, both the internal SORT and Werner's LSORT only look at the first sublist element when sorting a list containing sublists. So the final ordering should be sorted on that first sublist element, but all of the other sublist elements are ignored.

In this particular situation, you could work around that issue by converting the sublists to an integer using NL→I before sorting, then use I→NL to separate them again afterward. The only issue that will come up in that scenario is that you would lose leading 0s, so you'd have to add them back after the I→NL conversion. (hint: left-pad the lists with 0s and use 3 LLAST)

Note that this only works so long as all of the original list's elements are single digits. I→NL always breaks integers into lists of single digits, so this method won't work if any of the original sublist elements are > 9.

(08-06-2018 05:59 PM)pier4r Wrote:  What I did was a workaround. First getting the elements of the result list, without duplicates (it works), and then counting the occurrences of each element with LCNT (it works).
Below there is the code. The interesting part is at the end.

What I ask is: Could we have a LRPCT that does first LDDUP and then LCNT , to avoid sorting problems in the input list?

I'll think about that. No promises. Smile My first impression is that it is simply a special case that only requires a couple of UserRPL steps to do, so I'm not inclined to add a new command for it. But I'll consider it for the future (really, I will).

In the process of experimenting with this, you've shown me that there's a problem with the latest version of LDDUP. It was rewritten to improve efficiency, but the new version appears to fail when the elements being checked are sublists. I've tracked down the cause to the internal SysRPL command EQUALPOSMETA, which I now see treats sublists differently than discrete objects. Essentially, sublists never match with the latest version (and thus aren't culled out), even when they are exactly the same. So that command is broken in the latest release. I'll have to come up with a replacement for EQUALPOSMETA, as it doesn't provide the needed result if the objects being checked are sublists.

(@Eric, if you happen to see this note, please don't update ListExt to that 1.2.0 version I recently submitted. I'd prefer to fix this problem and re-submit a 1.2.1 release).

Regarding the actual modeling you're attempting:

Unless I'm mistaken, your current code only checks the distribution of results for 2 die, so you'd need a third level of nested loops for the third die. Am I understanding your code correctly?

I can think of some other approaches, but they'd probably be a mixed bag with performance. I should have some time later in the week to experiment with this.


RE: List Commands Library for 50g - pier4r - 08-08-2018 07:46 AM

(08-07-2018 01:47 PM)DavidM Wrote:  What's the purpose of the third element in the sublists? Is there a third potential item on each die (something other than a sword or "bam")?
Yes, there are also "diamons" with other dice. I keep everywhere 3 elements as I can have combinations of dice.

Quote:As far as I'm aware, both the internal SORT and Werner's LSORT only look at the first sublist element when sorting a list containing sublists. So the final ordering should be sorted on that first sublist element, but all of the other sublist elements are ignored.

In this particular situation, you could work around that issue by converting the sublists to an integer using NL→I before sorting, then use I→NL to separate them again afterward. The only issue that will come up in that scenario is that you would lose leading 0s, so you'd have to add them back after the I→NL conversion. (hint: left-pad the lists with 0s and use 3 LLAST)

Note that this only works so long as all of the original list's elements are single digits. I→NL always breaks integers into lists of single digits, so this method won't work if any of the original sublist elements are > 9.
Well it is an idea I didn't think about. But yes it could be that the sublist elements gets higher than 9 (say a 4 dice roll with a lot of "swords").
Actually, having the neat I\->NL and NL\->I , one could add math operations between lists (where a list is a list of single digits of a number), at least NL+ (number as list: add), NL-, NL*, NLIDIV (Integer division, let's make things easy at first). Of course then one can include all the possible functions, but having already the four basic integer functions would be golden honey made out of gold. It is a possible side project for listExt users!

Another possible idea is that I make sublists of 4 elements, where the first element represent the value of the remaining 3 elements. In this way SORT and LSORT could help, as they rely on the first element, although the code becomes a bit larger.

I was thinking there was a command that given a list would sort it through a userRPL/sysRPL command specified by the user but I was mistaken, it is not there. My idea was like: inputList sortProgram CSORT (custom sort)

Quote:In the process of experimenting with this, you've shown me that there's a problem with the latest version of LDDUP. It was rewritten to improve efficiency, but the new version appears to fail when the elements being checked are sublists. I've tracked down the cause to the internal SysRPL command EQUALPOSMETA, which I now see treats sublists differently than discrete objects. Essentially, sublists never match with the latest version (and thus aren't culled out), even when they are exactly the same. So that command is broken in the latest release. I'll have to come up with a replacement for EQUALPOSMETA, as it doesn't provide the needed result if the objects being checked are sublists.
I am sorry that you are getting down the rabbit hole of RPL. On the other side it is nice that we are pushing listExt so much! (and entirely by chance!) I like it.

Quote:Regarding the actual modeling you're attempting:

Unless I'm mistaken, your current code only checks the distribution of results for 2 die, so you'd need a third level of nested loops for the third die. Am I understanding your code correctly?

I can think of some other approaches, but they'd probably be a mixed bag with performance. I should have some time later in the week to experiment with this.

here: http://pier4r.wikidot.com/pierworks:articles:2018-08:massive-darkness-vanilla-dice

code: https://app.assembla.com/spaces/various-works-only-code/git-2/source/master/rpl_hp48-50/programs/general/urpl.diceMassiveDark

I started with for loops but I am lazy to adapt the code for each dice arrangement, so I created a recursive function to compute the roll of N dice.
At the moment the code - that may change - is the following.
Code:

gpRecursDiceRoll
  \<<
  
    \->
    @input
    lvDicePos
    
    \<<
      IF
        @if we are at the last dice
        lvDicePos gvNoDice ==
      THEN
        @roll the dice, but before increase the position to roll
        gpIncrDicePos
        
        @now the roll
        gvDiceComposition lvDicePos GET @dice type, we need another extraction
        gvDicePosActual lvDicePos GET @the position to get from the list in L1
        GET @leave the result on the stack
      ELSE
        @the position is smaller.
        @recurse first
        lvDicePos 1 + gpRecursDiceRoll
        
        @then extract the value
        gvDiceComposition lvDicePos GET @dice type, we need another extraction
        gvDicePosActual lvDicePos GET @the position to get from the list in L1
        GET @leave the result on the stack
        
        @and now add with the previous result on the stack
        ADD
      END
    \>>
  \>>

As usual I try first to be effective then to be efficient. I optimize things when I end up waiting too much. So far until 4 dice (1296 combinations, each with at least 4 recursion, so 5184 operations) is ok (it takes like 10 minutes on the real 50g).

I guess the main problem is, beside the processing of the data, how data is represented. If I represent it as sublist of 3 elements then I can use certain operations. If I represent it as vectors, I can use other operationsand so on. And this will help to be faster or slower according to the performance of the operations on certain type of data.

I used list as I know that the amount of available list processing operations is neat and so also development time shrinks. Development time being part of the solution time (running time actually is often a tiny fraction of the solution time).

For example if I use vectors to model the 3 possible results elements (that cannot be summed together), I have all the arithmetic operations but I cannot sort them (to then do LDDUP and LCNT, to get the frequency).
If I use strings, then I have way less available operations. For example when I want to sum the content between two strings keeping their position int the final result.
If I use numbers, then with a lot of sums could be that the original meaning of the digits is lost, and I have to carefully pads zeroes here and there. Besides a number is also more difficult to parse as result and to debug.

Therefore sublist of 3 elements is for me a good choice at the moment.