Author Topic: A skeleton code for Text Scroller via Drag-and-Drop  (Read 30008 times)

0 Members and 1 Guest are viewing this topic.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #45 on: July 25, 2021, 05:50:05 am »
Enter Gesch encoding...

It's time to break away, no more limitations on browsing Italian/French/German/Spanish/Bulgarian/Russian ... without using any UNICODE!

In next days will write the search panel in which all those symbols (from my Gesch codepage), for now I wrote only the converter from UTF-8 to Gesch, attached at the end.

Here it is the "legacy" codepage, which in my opinion was made by a total schmuck:

 
GeschA.png


Here is the newwave in codepage encodings :P

 
GeschB.png


As always, I checked all the converted symbols against the https://utf8-chartable.de, and there were no mismatches:

 
Gesch1.png


 
Gesch2.png


One quick example is how Don Quixote is readable in Gesch encoding:

 
spanish1.png


Simply, when I need to browse some UTF-8 file, I won't be bothered whether there are Russian or/and French or/and German texts within, just will run UTF8toGesch.exe converter and Drag-n-Drop the .Gesch file.
In next releases will add the ability to search for those symbols.

Halving the file size comes as a "side effect", as a bonus. For example I have one Russian corpus 15,000+ ebooks in UTF-8 strong and 11GB in size. Guess what, instead of fulltext searching 11GB in UTF-8 the traverse distance becomes ~6GB.
* MASAKARI_r8.1.7z (Filesize: 4.32 MB, Downloads: 380)
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #46 on: July 28, 2021, 12:30:02 pm »
The need for more ergonomic (that is, easily accessible) shortcuts (strictly keyboardish) got me thinking...

Holy hell, why no one introduced the analogues/counterparts of "double-clicks" - the first that comes to mind: the "double-hits".
Both, being just taps.
Currently, in Masakari there are:
- shortcuts, purely keyboardish;
- shortcuts, mix of keys and mouse buttons;
- shortcuts, purely mouseish, just mouse stuff - buttons and wheel.

From revision 8.1+ onward, following double-hits were implemented:
Double LShift; Double LCtrl; Double LAlt; Double RAlt.
The thing is that "legacy" shortcuts as Ctrl+F3 (even the F3) force the user to "locate" their position and to overreach - meaning hovering pass the SPACEBAR area - which is most easy to hit since the wrists/palms have support, and are simply closer.
To me, the traditional key sequences are to be replaced/enriched with more convenient, more close to the first row of the keyboard, ones.
Currently, my main keyboard is a nasty one (laptopish, with low profile, non-tactile, half-sized F-keys, and tightly packed), when e.g. a LCtrl+F3 search is needed, spotting this halved F3 is a drag, therefore the double-hit of e.g. LCtrl saves the situation - just double-tap it - the timings between the two pressings are handled by the same logic as the mouse double/triple/quadruple-clicks.
The following stand-alone etude is the same as the previously shared mouse_mumbo-jumbo.bas, except:
Code: QB64: [Select]
  1. buttondown1 = _MOUSEBUTTON(1)
should be replaced with
Code: QB64: [Select]
  1. KeyTap_buttondown1 = _KEYDOWN(LSHIFTkey&)

The attached package contains the most refined revision so far, with all accompanying  tools, 32bit and 64bit executables for Windows, and 64bit ELF for Linux.
There is one file, called Word-list_584879_words_Russian_Spell-Check.txt.Gesch.oneline.198, it serves as a scroll line-by-line testfile benchmark, on my laptop running both Windows 10 and Fedora 33, it gave 45 Lines-Per-Second scroll speed:

 
MASAKARI_r8.1+_Fedora_Screenshot_showing_F2.png


And the PDF booklet with the QB64 sourcecode at:
www.sanmayce.com/Masakari.zip

 
qb_post.png

* MASAKARI_r8.1+_LITE.7z (Filesize: 18.21 MB, Downloads: 407)
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #47 on: October 12, 2021, 07:45:33 am »
My word is for QB64 toolbox/application enrichment.

Didn't want to initiate a thread about hashing, especially for having the so needed fastest 128bit hash function.
As the need for speed is constantly on my mind, recently I wrote Gumbotron:
https://github.com/google/highwayhash/issues/102#

 
Gumbotron_.png


The idea is to solve problematic search/index scenarios with reliable/optimized tools/etudes and feeding the QB64 application with resultant data.
Too often 1,000,000,000 records e.g. 64,128 or 256 bytes long are to be searched, how to deal with it?!
The discussions in other sub-forums focus on languages and their advance features, but the problem stays as long as one sees within the box and forgets to look outwith, that is, beyond the languages limitations.
Gumbotron is such a case, it makes the hashing in inside-out not in outside-in manner, meaning all the permutations of the key for hashing are dealt with outside the hasher itself, the "traditional" hashers make all kind of rotations/multiplications/shifts within the body serving as a LINEAR MIXER, but the really smart coders already did such a LINEAR MIXER hardwarely embedding all the stages of AES into a single instruction with latency 3 clocks and throughput 1 clock!
So, the moral is to exploit all the available resources (either languages, CPU extensions, algorithms), not to burden oneself with giving tasks as forcing a dog to pull a plug, yes the ox is better, but dog has other functionality - it is a matter of proper assignment.

Hm, don't feel I am getting my point across, back in the day Assembler/Assembly was popularized by the "bad guy" Phil Katz, the documentary says a lot. The favorite part of mine is where the screen says "... the damage was done" referring to speeding up the ARC 10x, rewriting C parts into Assembly. Very funny and sad at the same time, the bad guy gives PKARC/PKZIP and teaches in a practical way how things are to be done, and the community slams him as being the devil. If the devil offers superspeeds, let us reject them since they are ... born in sin, hee-hee.



Also, reading, in the forum, the discussion about highlighting/popularizing the usefulness of QB64, didn't want to write obvious things, yet to me the most obvious way is by ... example.
Yes, sharing etudes/tools written well with real practical value would showcase the power of one approach/language/method in a macho (Clint Eastwood's last film taught me this word) way.
Imagine, a well-written tool, it would serve as an ad for the language used, quite naturally. Having such a good forum prompts for sharing code that catches the attention of users and makes them enthusiasts, daring to try themselves, but they have to have a starting point/code/tool to play with.
Will share this thread/tool on the biggest English language forum:
https://forum.thefreedictionary.com/postst31183p4_MASAKARI--The-people-s-choice--General-Purpose-Grade--English-wordlist.aspx

And just wanted to announce the incoming new Masakari revision allowing dictionaries lookups in a better way than most software out there, including the original Oxford, Webster, Wiktionary...
My vision is to present all the .DSL files into an unified/standardized manner, simplistic and ergonomic, having in mind cross-searches as well.
The draft looks like this (yes, targeting the old and super durable laptops, as Thinkpad, having low resolutions as 1366x768):

 
Masa_oed.png


Writing such a practical tool (allowing quick lookups into 16+1+1+1 major dictionaries) could serve as a starting point for contemplating new ideas of refining and boosting the search capabilities even more...

I intend gradually to add all these:
Code: QB64: [Select]
  1. 02/28/2021  08:34 PM        42,257,313 Dictionary_Specification_Language_(ABBYY_Software_House)_American_Heritage_Dictionary_4_(En-En)_UTF-8.dsl
  2. 02/28/2021  08:36 PM       299,225,953 Dictionary_Specification_Language_(ABBYY_Software_House)_Britannica_Encyclopedia_2010_1.563_miled_(En-En)_ANSI.dsl
  3. 02/28/2021  08:58 PM        75,122,799 Dictionary_Specification_Language_(ABBYY_Software_House)_Cambridge_Advanced_Learner's_Dictionary_4th_Ed_(En-En).dsl
  4. 02/28/2021  09:00 PM        23,413,283 Dictionary_Specification_Language_(ABBYY_Software_House)_Collins_COBUILD_Advanced_Learner's_English_Dictionary_(5th_ed)_(En-En).dsl
  5. 02/28/2021  09:05 PM        37,870,978 Dictionary_Specification_Language_(ABBYY_Software_House)_Longman_Activator_2nd_Ed_(En-En).dsl
  6. 02/28/2021  09:10 PM        52,743,002 Dictionary_Specification_Language_(ABBYY_Software_House)_Longman_Dictionary_of_Contemporary_English_5th_Ed_(En-En).dsl
  7. 02/28/2021  09:19 PM        83,412,925 Dictionary_Specification_Language_(ABBYY_Software_House)_Macmillan_English_Dictionary_(En-En)_UTF-8.dsl
  8. 02/28/2021  09:19 PM        29,772,872 Dictionary_Specification_Language_(ABBYY_Software_House)_Macmillan_English_Thesaurus_(En-En)_UTF-8.dsl
  9. 02/28/2021  09:15 PM       101,528,058 Dictionary_Specification_Language_(ABBYY_Software_House)_Merriam-Webster's_Collegiate_Dictionary_11th_Edition_(En-En).dsl
  10. 02/28/2021  09:29 PM        57,854,694 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_Advanced_Learner's_Dictionary_8th_Edition_(En-En).dsl
  11. 02/28/2021  09:32 PM        44,362,425 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_American_Dictionary_2nd_Edition.dsl
  12. 02/28/2021  09:33 PM        11,747,238 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_American_Thesaurus_(En-En).dsl
  13. 02/28/2021  09:38 PM       559,408,265 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_English_Dictionary_2nd_Edition_Version_4_(En-En)_ANSI.dsl
  14. 02/28/2021  09:33 PM        53,483,030 Dictionary_Specification_Language_(ABBYY_Software_House)_Random_House_Webster's_Unabridged_Dictionary_(En-En)_UTF-8.dsl
  15. 02/28/2021  09:53 PM        12,202,934 Dictionary_Specification_Language_(ABBYY_Software_House)_The_Collins_Cobuild_School_Dictionary_of_American_English_(En-En).dsl
  16. 02/28/2021  08:26 PM       137,754,899 Dictionary_Specification_Language_(ABBYY_Software_House)_Webster's_Unabridged_3_(En-En)_UTF-8.dsl
  17.  
  18. 03/28/2019  02:31 PM         5,340,386 dict2txt_Online_Etymology_Dictionary1.1.txt
  19.  
  20. 10/08/2021  08:42 AM     7,015,793,795 enwiktionary-20210920-pages-articles.xml
  21.  
  22. 07/10/2021  09:57 PM     1,917,822,288 Machine-Learning_Urban_Dictionary_Definitions_Corpus_(1999_-_May-2016).words.json
  23.  

For a long time, the need for English language speedy lookups into constellation of dictionaries (on a netbook) drives me toward writing a tool sidekicking macholy, once and for all.
« Last Edit: October 12, 2021, 08:22:20 am by Sanmayce »
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #48 on: October 23, 2021, 11:22:27 pm »
Thanks @The Librarian for sharing this:
https://www.qb64.org/forum/index.php?topic=1598.0

This function is a must-have, for example it can be used for controlling _LIMIT in a "stepping" fashion, as the CPUs are downclocked.

Consider a main loop with _LIMIT 500 and the user is using the application touch-and-go-ly, it is a good idea to reduce the 500 by 10% each minute (down to 90%) of inactiveness i.e. not doing keyboard input.

Here is a bit modified variant, after 13 minutes it enters maximum ... minimum:

 
epoch2.png


Already incorporated this etude in Masakari r.8.1++, also finished the Schizandrafield rev.D lookup functionality:

 
M81++_1.png


Simple functionalities such as automatic highlighting of identical entries (above and below) to the current/inverse line are nice since the eyes stop constantly seeking whether neighbors are identical.

Also, finally, did what every GUI tool has to offer - the Color Scheme defined in a file (allowing the user to play with it), in this case the file is called Masakari.RGB - it is 48 bytes long, all the 16 colors given from 0 to 15 in three bytes sequence, RGB:

 
RGB3.png


Sometimes, when working outdoors (on a shiny day), more brightness is needed, laptops lack such a regulator so just pressing 'I' will increase all channels by 1 point:

 

The feeling, of seeing the actual window colorized, is different from seeing some small box, moreover the combinations of foreground and background are tricky to please the user, therefore one can play with channels and intensity and once seeing a pleasing combination then can save the RGB values on paper and remap whichever color in the Masakari.RGB is wanted to be replaced.
* EpochStepping.bas (Filesize: 1.96 KB, Downloads: 331)
RGB1.png
* RGB1.png (Filesize: 544.92 KB, Dimensions: 1577x750, Views: 499)
« Last Edit: October 23, 2021, 11:44:17 pm by Sanmayce »
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #49 on: October 30, 2021, 08:42:14 am »
What is the quicksort routine that QB64 community uses?!

Back in the day, I wrote an XMS QuickSort, now dusted off and shared here.
From time to time, I visit the very informative site 'rosettacode' where multi languages etudes are given side by side, it is a shame QB64 is not presented there as it should, especially unacceptable is the situation with the QS64, standing for QuickSort 64bit, not having its QB64  presence.
Today, I have added my Quicksort variant, thus putting QB64 in this must-be "Quick" category:

https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#QB64

Soon will include this very subroutine into Masakari sorting the QWORD  long indexes to lines...

Also, did make a benchmark (source code and binary attached) with QB64 executable which can be used as a general speed benchmark, stressing caches and somewhat uncached (or rather not well cached) RAM accesses (despite QS being with good locality) - very interesting it would be when AMD 3D cache comes along, and mostly with M1 Apple's unified memory (with RAM latency ~35ns being the half of PCs, AFAIK).
Whoever owns M1 Max, please compile it and share with us how well Apple performs.

On my Kaby Lake laptop (i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz) it took 11 minutes to sort 1.7 billion QWORDS (i.e. 8 bytes elements). They are in range 0..9, which makes sorting harder due to the many repetitions.

Here we go:

 
qs1.png


The panel at the end checks for sanity:

 
qs3.png


Actually, the digits come from the 22,338,618 bytes long file containing the dump of 2^74207281-1, which was the biggest known prime number in 2016.

Here is the dumper of my testdataset, thanks to Fabrice Bellard:
Code: C++: [Select]
  1. // https://bellard.org/mersenne.html
  2. // A small C program to print the biggest prime number
  3. // Here it is (448 bytes):
  4. /*
  5. int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<
  6. 25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]
  7. =(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}main(){while(e/=2){N*=2
  8. ;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;
  9. for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a%10,a/=10;
  10. }while(!*--p);for(t[0]--;p>=t;)putchar(48+*p--);}
  11. */
  12. // This program computes 2^74207281-1, which was the biggest known prime number in 2016 (about 23 million digits !). For more information about how it was // found and who found it, look at the GIMPS Project .
  13. //
  14. // I compiled it successfully with gcc with Linux. In order to compile it, your C compiler must support the 64 bit long long type.
  15. //
  16. // In order to have a small and yet asymptotically efficient code, I decided to do the computation of 2N-1 directly in base 10. The power involves repeated // squarings and multiplications by two. The squarings are implemented by doing fast convolutions using a Number Theoretic Transform.
  17. //
  18. // A previous version of this program to compute 2^6972593-1 won the International Obfuscated C Code Contest of Year 2000.
  19. //
  20. // Thanks to Marco Cecchi who suggested some syntactic changes to save a few characters.
  21. //
  22. // This program is Freeware.
  23. //
  24. // Fabrice Bellard - http://bellard.org/
  25. // last update: Sep 26, 2016
  26.  
* Quicksort_says.zip (Filesize: 15.35 MB, Downloads: 336)
He learns not to learn and reverts to what all men pass by.

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #50 on: October 30, 2021, 09:58:06 am »
From time to time, I visit the very informative site 'rosettacode' where multi languages etudes are given side by side, it is a shame QB64 is not presented there as it should, especially unacceptable is the situation with the QS64, standing for QuickSort 64bit, not having its QB64  presence.
yes I agree, here's one for the graphics experts https://rosettacode.org/wiki/Honeycombs

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #51 on: October 30, 2021, 11:46:22 am »
Quote
What is the quicksort routine that QB64 community uses?!

I've been using a recursive QuickSort, eg for Single Type:
Code: QB64: [Select]
  1. Sub QuickSort (start As Long, finish As Long, array() As Single)
  2.     Dim Hi As Long, Lo As Long, Middle As Single
  3.     Hi = finish: Lo = start
  4.     Middle = array((Lo + Hi) / 2) 'find middle of array
  5.     Do
  6.         Do While array(Lo) < Middle: Lo = Lo + 1: Loop
  7.         Do While array(Hi) > Middle: Hi = Hi - 1: Loop
  8.         If Lo <= Hi Then
  9.             Swap array(Lo), array(Hi)
  10.             Lo = Lo + 1: Hi = Hi - 1
  11.         End If
  12.     Loop Until Lo > Hi
  13.     If Hi > start Then Call QuickSort(start, Hi, array())
  14.     If Lo < finish Then Call QuickSort(Lo, finish, array())

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #52 on: October 30, 2021, 11:48:00 am »
yes I agree, here's one for the graphics experts https://rosettacode.org/wiki/Honeycombs

I did that one a couple years ago in JB.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #53 on: November 01, 2021, 04:59:07 am »
@jack
Glad that you also see the miss, will try to share rev.3 which will feature an unseen partitioning, hopefully helping in scenarios with duplicative keys almost dominating the array...

@bplus
Thanks, that's what I need, variants of QB64 community helping in refining the current fastest ones.
Since my focus is on 64bit file/string manipulations (as in the example with Wikipedia XML ~74GB having 1+billion lines), all LONG variables are obsolete i.e. 2 billion (signed, you know) are limiting dealing with big data. So, I have included your tiny (modified to be 64bit) variant as performer #3, thus we can see how my (rev.1) published on ROSETTACODE fares against yours, also as performer #2, I have put rev.2 boosting speed by just finishing with Insertionsort (nothing new), my dummy logic was to choose 7999 elements long chunks unsorted, because 7999*8<64KB, hoping the L1 data cache can house it. I have an idea to write entirely new partitioning in rev.3, we will see in practice its behavior.

Run/Performer #3 proves slower than the ROSETTACODE QB64 etude:

Code: QB64: [Select]
  1. Sub QuickSort (start As _Integer64, finish As _Integer64, array() As _Integer64)
  2.     Lo = start: Hi = finish
  3.     Middle = array((Lo + Hi) \ 2)
  4.     Do
  5.         Do While array(Lo) < Middle: Lo = Lo + 1: Loop
  6.         Do While array(Hi) > Middle: Hi = Hi - 1: Loop
  7.         If Lo <= Hi Then
  8.             Swap array(Lo), array(Hi)
  9.             Lo = Lo + 1: Hi = Hi - 1
  10.         End If
  11.     Loop Until Lo > Hi
  12.     If Hi > start Then Call QuickSort(start, Hi, array())
  13.     If Lo < finish Then Call QuickSort(Lo, finish, array())
  14.  

It would be nice fellow members to share their ideas and benchmarks, so we can pair the QuickBasic64 with QuickSort64.

Here comes the 32bit code generated by QB64 v.2.01, Core 2 Duo 2.9GHz, DDR2 266MHz:

 
qs_32bit.png


Here comes the 64bit code generated by QB64 v.2.01, i5-7200U 3.1GHz, DDR4 1066MHz:

 
qs5.png


Wanna see modern machines running this benchmark in order to get the picture more clearly...
* Quicksort_says_rev2.zip (Filesize: 15.36 MB, Downloads: 409)
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #54 on: November 07, 2021, 08:24:10 am »
Glad to share my latest refinement, source code and the two binaries (for Linux and Windows) are in the attached package.
Here comes the new Quicksort rev.3 with the new 'Magnetica' partitioning, compared side-by-side with the mainstream recursive Quicksort with 'Classica' partitioning.
Generally, we have three major scenarios:
- FEW distinct keys;
- MANY distinct keys;
- ALL distinct keys.

In first two cases, the new implementation is faster or equal to the "Standard" one:

Under Windows:

 
Quicksort_says_rev3_Kaby-Lake_Windows-10.png


Under Linux:

 
Quicksort_says_rev3_Kaby-Lake_Fedora-33.png


Sadly, in the third case, it is somewhat slower.
Anyway, benchmarking will show the practical value of 'Magnetica', personally, I started to use it already.
* Quicksort_says_rev3.7z (Filesize: 16.72 MB, Downloads: 364)
« Last Edit: November 07, 2021, 08:53:45 am by Sanmayce »
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #55 on: November 16, 2021, 03:40:05 pm »
Having been "side-tracked" by tuning my old function for two weeks, resulted in writing, by chance, the FASTEST Quicksort, known to me.

 
Quicksort Showdown.pdf.png


Enjoy!
* Quicksort Showdown.pdf (Filesize: 1.68 MB, Downloads: 293)
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #56 on: November 21, 2021, 07:47:54 pm »
One can learn, in a lazy manner, a lot just by seeing the sort being ... animated.

Couldn't resist not to make a video showing the beautiful Magnetica train - the actual visualized sort process.

The sorting pauses for 3 seconds each time when the orange train collides with the Jndx - the right "sentinel" colored in red.

I chose for the testfile an old interview in English, ~27KB long, the window/matrix for sorting is 300 columns x 80 lines <27KB.
This type of sorts are quite useful in compression/indexing since each position demands statistics for order 1..8 bytes long Building-Blocks, inhere we sort order 1 i.e. letters.

For more fun, added Quicksort 'Classica' recursive dealing with the same array, the interesting thing here is one to compare Classica's Swaps and Comparisons versus Magnetica's ones:



Magnetica: 66,008 and 115,721
Classica: 132,663 and 355,221

Total Smackdown.
* Quicksort_matrix_rev1.zip (Filesize: 931.44 KB, Downloads: 257)
« Last Edit: November 21, 2021, 08:00:48 pm by Sanmayce »
He learns not to learn and reverts to what all men pass by.

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #57 on: November 25, 2021, 11:32:16 pm »
The attached C function is the fastest quicksort I could write, so far.

Thanks to PCBoy Studios, here comes a short animated demo of Quicksort 'Magnetica' (initial release):



Now, the new function is more robust against quadratic behavior, since it was strengthened with median of 5 pivot - branchlessly on top of that!

And for all fellow members who need maximum speed in their sorting, here comes the usage of the "header" written in C, ready to go in QB64:

Code: QB64: [Select]
  1.     Sub Quicksort_QB64_v5 (ByVal QWORDS As _Offset, Byval Left As _Integer64, Byval Right As _Integer64)
  2.  
  3. Quicksort_QB64_v5 _Offset(QWORDS~&&(LBound(QWORDS~&&))), 0, UBound(QWORDS~&&) - LBound(QWORDS~&&)
  4.  

Enfun!

Oh, and  @bplus your recursive quicksort crashes (with mere 100,000 elements) without even giving an error on exit, it occurs with 'Organ Pipe' data. Your test program modified is given below in order to reproduce the crash. My advice, start using the attached QB64 "intrinsic", updated on 2021-Nov-28:

 
organpipe.png


Code: QB64: [Select]
  1.     Sub memcpy (ByVal dest As _Offset, Byval source As _Offset, Byval bytes As Long)
  2.  
  3. _Title "Recursive Vrs NonRecursive test with Quicksort" 'b+ 2021-11-01, Sanmayce added some stuff 2021-Nov-26
  4. ArrayHigh = 2 * 50000
  5. 'ArrayHigh = 2 * 5000000
  6. ReDim Shared As _Unsigned _Integer64 n(1 To ArrayHigh), m(1 To ArrayHigh), z(1 To ArrayHigh) 'z(0 To ArrayHigh - 1)
  7.  
  8. Declare CustomType Library "qsm" ' Notice that 'CustomType' makes things work, using 'STATIC' gives errors during compilation
  9.     Sub Quicksort_QB64_v5 (ByVal QWORDS As _Offset, Byval Left As _Integer64, Byval Right As _Integer64)
  10.  
  11. 'For i = 1 To ArrayHigh
  12. '    n(i) = i '13 'i
  13. 'Next
  14. 'For i = ArrayHigh To 2 Step -1 ' Fisher Yates Shuffle
  15. '    Swap n(i), n(Int(Rnd * i) + 1)
  16. '    m(i) = n(i) ' copy m off n
  17. '    z(i) = n(i) ' copy m off n
  18. 'Next
  19.  
  20. ' Generate 'OrganPipe' data:
  21. For i = 1 To ArrayHigh
  22.     If i <= ArrayHigh \ 2 Then
  23.         n(i) = i
  24.         m(i) = n(i) ' copy m off n
  25.         z(i) = n(i) 'z(i - 1) = n(i) ' copy m off n
  26.     Else 'ArrayHigh \ 2 + 1 .. ArrayHigh
  27.         n(i) = ArrayHigh - i + 1
  28.         m(i) = n(i) ' copy m off n
  29.         z(i) = n(i) 'z(i - 1) = n(i) ' copy m off n
  30.     End If
  31. 'Print z(1), z(2)
  32. 'Print z(ArrayHigh - 1), z(ArrayHigh)
  33.  
  34.  
  35. a$ = "1234567890"
  36. b$ = "ABCDEFGHIJ"
  37.  
  38. memcpy _Offset(a$) + 1, _Offset(z(1)), 8
  39. memcpy _Offset(a$) + 1, _Offset(z(ArrayHigh)), 8
  40.  
  41. Print "Test arrays ready. Testing Recursive QuickSort first."
  42. 'n(1) = ArrayHigh
  43. 'm(1) = n(1)
  44. 'z(1) = n(1)
  45.  
  46. 'crashes with OrganPipe
  47. T# = Timer(.001)
  48. QuickSort 1, ArrayHigh
  49. QuickSortT# = Timer(.001) - T#
  50. For i = 1 To ArrayHigh - 1
  51.     If n(i) > n(i + 1) Then Print "NOT OK!": End
  52. Print "QuickSort checked, QuickSort time was"; QuickSortT#
  53. 1
  54.  
  55. T# = Timer(.001)
  56. Quicksort_QB64
  57. QuicksortQB64T# = Timer(.001) - T#
  58. For i = 1 To ArrayHigh - 1
  59.     If m(i) > m(i + 1) Then Print "NOT OK!": End
  60. Print "Quicksort_QB64 checked, Quicksort_QB64 time was"; QuicksortQB64T#
  61.  
  62.  
  63. 'T# = Timer(.001)
  64. 'Quicksort_QB64_v2
  65. 'QuicksortQB64T# = Timer(.001) - T#
  66. 'For i = 1 To ArrayHigh - 1
  67. '    If z(i) > z(i + 1) Then Print "NOT OK!": End
  68. 'Next
  69. 'Print "Quicksort_QB64_v2 checked, Quicksort_QB64_v2 time was"; QuicksortQB64T#
  70.  
  71. Print LBound(z), UBound(z), ArrayHigh
  72. 'Print _Offset(z(0))
  73. Print _Offset(z(1)), _Offset(z(LBound(z)))
  74. 'Print _Offset(z(2))
  75.  
  76. T# = Timer(.001)
  77. Quicksort_QB64_v5 _Offset(z(LBound(z))), 0, UBound(z) - LBound(z) ' with 'STATIC' library: error: invalid conversion from 'unsigned int' to 'void*' [-fpermissive] Quicksort_QB64_v4(((uptrszint)((&(((uint64*)(__ARRAY_UINTEGER64_QWORDS[0]))
  78. QuicksortQB64Tv5# = Timer(.001) - T#
  79.  
  80. Print z(1), z(2), z(3), z(4), z(5)
  81. Print z(ArrayHigh - 1), z(ArrayHigh)
  82.  
  83. For i = 1 To ArrayHigh - 1
  84.     'If z(i - 1) > z(i - 1 + 1) Then Print "NOT OK!": End
  85.     If z(i) > z(i + 1) Then Print "NOT OK!": End
  86. Print "Quicksort_QB64_v5 checked, Quicksort_QB64_v5 time was"; QuicksortQB64Tv5#
  87.  
  88. Print: Print "Verdict: On 'OrganPipe' data, QuicksortQB64v5 (in C) is "; Int(QuicksortQB64T# / QuicksortQB64Tv5#); "times faster than QuicksortQB64 (in QB64)."
  89.  
  90. ' recursive
  91. Sub QuickSort (start As _Unsigned _Integer64, finish As _Unsigned _Integer64)
  92.     Lo = start: Hi = finish
  93.     Middle = n((Lo + Hi) \ 2)
  94.     Do
  95.         Do While n(Lo) < Middle: Lo = Lo + 1: Loop
  96.         Do While n(Hi) > Middle: Hi = Hi - 1: Loop
  97.         If Lo <= Hi Then
  98.             Swap n(Lo), n(Hi)
  99.             Lo = Lo + 1: Hi = Hi - 1
  100.         End If
  101.     Loop Until Lo > Hi
  102.     If Hi > start Then QuickSort start, Hi
  103.     If Lo < finish Then QuickSort Lo, finish
  104.  
  105. ' non recursive
  106. ' ref:  https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#QB64
  107. Sub Quicksort_QB64
  108.     Left = LBound(m)
  109.     Right = UBound(m)
  110.     LeftMargin = Left
  111.     ReDim Stack&&(Left To Right)
  112.     StackPtr = 0
  113.     StackPtr = StackPtr + 1
  114.     Stack&&(StackPtr + LeftMargin) = Left
  115.     StackPtr = StackPtr + 1
  116.     Stack&&(StackPtr + LeftMargin) = Right
  117.     Do 'Until StackPtr = 0
  118.         Right = Stack&&(StackPtr + LeftMargin)
  119.         StackPtr = StackPtr - 1
  120.         Left = Stack&&(StackPtr + LeftMargin)
  121.         StackPtr = StackPtr - 1
  122.         Do 'Until Left >= Right
  123.             Pivot~&& = m((Left + Right) \ 2)
  124.             Indx = Left
  125.             Jndx = Right
  126.             Do
  127.                 Do While (m(Indx) < Pivot~&&)
  128.                     Indx = Indx + 1
  129.                 Loop
  130.                 Do While (m(Jndx) > Pivot~&&)
  131.                     Jndx = Jndx - 1
  132.                 Loop
  133.                 If Indx <= Jndx Then
  134.                     If Indx < Jndx Then Swap m(Indx), m(Jndx)
  135.                     Indx = Indx + 1
  136.                     Jndx = Jndx - 1
  137.                 End If
  138.             Loop While Indx <= Jndx
  139.             If Indx < Right Then
  140.                 StackPtr = StackPtr + 1
  141.                 Stack&&(StackPtr + LeftMargin) = Indx
  142.                 StackPtr = StackPtr + 1
  143.                 Stack&&(StackPtr + LeftMargin) = Right
  144.             End If
  145.             Right = Jndx
  146.         Loop Until Left >= Right
  147.     Loop Until StackPtr = 0
  148.  
  149.  
  150. Sub Quicksort_QB64_v2
  151.  
  152.     InsertionsortTHRESHOLD = 0 '19
  153.     Left = LBound(z)
  154.     Right = UBound(z)
  155.     ReDim Stack&&(Left To Right)
  156.     StackPtr = 0
  157.     StackPtr = StackPtr + 1
  158.     Stack&&(StackPtr + LeftMargin) = Left
  159.     StackPtr = StackPtr + 1
  160.     Stack&&(StackPtr + LeftMargin) = Right
  161.     Do 'Until StackPtr = 0
  162.         Right = Stack&&(StackPtr)
  163.         Left = Stack&&(StackPtr - 1)
  164.         StackPtr = StackPtr - 2
  165.         Do 'Until Left >= Right
  166.  
  167.             ''Classica' partitioning [
  168.             'Pivot~&& = z((Left + Right) \ 2)
  169.             'Indx = Left
  170.             'Jndx = Right
  171.             'Do
  172.             '    Do While (z(Indx) < Pivot~&&)
  173.             '        Indx = Indx + 1
  174.             '    Loop
  175.             '    Do While (z(Jndx) > Pivot~&&)
  176.             '        Jndx = Jndx - 1
  177.             '    Loop
  178.             '    If Indx <= Jndx Then
  179.             '        If Indx < Jndx Then Swap z(Indx), z(Jndx)
  180.             '        Indx = Indx + 1
  181.             '        Jndx = Jndx - 1
  182.             '    End If
  183.             'Loop While Indx <= Jndx
  184.             ''Classica' partitioning ]
  185.  
  186.             ' 'Magnetica' partitioning [
  187.             Jndx = Right
  188.             PL = Left
  189.             PR = Left
  190.             Swap z((Left + Right) \ 2), z(PR) 'Swap z(Left + (Right - Left) \ 4), z(PR)
  191.             Pivot~&& = z(PR)
  192.             Do While PR < Jndx
  193.                 If Pivot~&& > z(PR + 1) Then
  194.                     Swap z(PL), z(PR + 1)
  195.                     PL = PL + 1
  196.                     PR = PR + 1
  197.                 ElseIf Pivot~&& = z(PR + 1) Then
  198.                     PR = PR + 1
  199.                 Else ' < i.e. Pivot~&& < z(PR + 1)
  200.                     Do While Pivot~&& < z(Jndx)
  201.                         Jndx = Jndx - 1
  202.                     Loop
  203.                     If PR + 1 < Jndx Then Swap z(PR + 1), z(Jndx)
  204.                     Jndx = Jndx - 1
  205.                 End If
  206.             Loop
  207.             Jndx = PL - 1
  208.             Indx = PR + 1
  209.             ' 'Magnetica' partitioning ]
  210.  
  211.             If Indx + InsertionsortTHRESHOLD < Right Then 'if the remaining chunk is bigger than 'InsertionsortTHRESHOLD' push it to stack, otherwise leave all such chunks unsorted
  212.                 StackPtr = StackPtr + 2
  213.                 Stack&&(StackPtr - 1) = Indx
  214.                 Stack&&(StackPtr) = Right
  215.             End If
  216.             Right = Jndx
  217.         Loop Until Left >= Right
  218.     Loop Until StackPtr = 0
  219.     'Left = LBound(z)
  220.     'Right = UBound(z)
  221.     'For i = Left + 1 To Right ' i.e. 1 to size-1 omitting the first (which is 0)
  222.     '    j = i
  223.     '    Do While j >= 1 'Nah, start using a sentinel
  224.     '        If z(j - 1) > z(j) Then Swap z(j - 1), z(j) Else Exit Do
  225.     '        j = j - 1
  226.     '    Loop
  227.     'Next i
  228.  

* qsm.h (Filesize: 15.29 KB, Downloads: 162)
« Last Edit: November 28, 2021, 01:03:49 am by Sanmayce »
He learns not to learn and reverts to what all men pass by.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #58 on: November 26, 2021, 12:21:35 pm »
Quote
Oh, and  @bplus your recursive quicksort crashes (with mere 100,000 elements) without even giving an error on exit,

Did 100,000,000 items for me without mods:
 
100 000 000 items.PNG

Offline Sanmayce

  • Newbie
  • Posts: 63
  • Where is that English Text Sidekick?
    • View Profile
    • Sanmayce's home
Re: A skeleton code for Text Scroller via Drag-and-Drop
« Reply #59 on: November 28, 2021, 05:44:30 pm »
Did 100,000,000 items for me without mods:

You didn't notice what the QB64 snippet holds, in above post. It is your test, but modified to sort 'Organ Pipe' instead of 'Random' dataset. It crashes with 100,000 using QB64 32bit. It is interesting to see how much QB64 64bit can handle before crashing. Beside this, qsm.h is from 11x to 2x faster, that's why I recommend it. In the screenshot below, Run #1 is your QB64 code, whereas Run #2 is qsm.h:

 
qss_r6.png


Code: QB64: [Select]
  1. Laptop Intel i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz:
  2. +--------------------+---------------------------+---------------------------+---------------------------+
  3. | Performer/Keys     | FEW distinct              | MANY distinct             | ~ALL distinct             |
  4. +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+
  5. |  Operating System, | Windows 10, | Fedora 33,  | Windows 10, | Fedora 33,  | Windows 10, | Fedora 33,  |
  6. |      Compiler, -O3 | Intel v15.0 | GCC 10.2.1  | Intel v15.0 | GCC 10.2.1  | Intel v15.0 | GCC 10.2.1  |
  7. +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+
  8. | qsort              |  58 seconds | 360 seconds | 343 seconds | 535 seconds | 444 seconds | 519 seconds |
  9. | Magnetica r.2      |  35 seconds |  35 seconds | 214 seconds | 222 seconds | 271 seconds | 286 seconds |
  10. | Bentley-McIlroy    |  39 seconds |  41 seconds | 203 seconds | 230 seconds | 275 seconds | 313 seconds |
  11. +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+
  12. Legend (The time is exactly the Sort process time):
  13. FEW = 2,233,861,800 keys, of them distinct = 10;
  14. MANY = 2,482,300,900 keys, of them distinct = 2,847,531;
  15. ~ALL = 2,009,333,753 keys, of them distinct = 1,912,608,132
  16.  

Quick highlights:
- GLIBC's qsort is just trash;
- Intel's qsort is trashy;
- Bentley-McIlroy is good, however the disassembly (-O3) shows many weird vector instructions used, not good for a scalar code;
- Magnetica r.2 is nice, the disassembly (-O3) gladdens the eyes.

Finally, wanted all fellow members, interested in writing their own "intrinsics" (in its original sense - "essential"), to have one booklet showing how much C code can reinforce the QB64 muscle flexing:

 
qsm_pdf.png


With this my Quicksort detour is completed.
* Quicksort Showdown2.pdf (Filesize: 3.85 MB, Downloads: 180)
He learns not to learn and reverts to what all men pass by.