« first day (1438 days earlier)      last day (1217 days later) » 

12:33 AM
If Adam was here he'd tell you to use a tradfn
If that's real code and not just an example, you can do {⊃(⍺⍵)⌽⍨(⍵<3)=(⍺=⍵)} (I think)
 
 
5 hours later…
5:19 AM
@user I think several other APL's support it. Kap certainly does.
 
 
2 hours later…
7:31 AM
@user Closer analogy would be Haskell's if-then-else expressions (not statements), which is definitely nice to have (at least for me)
 
7:53 AM
@Bubbler In Kap, you can actually do a ← if(x) {y} else {z}
 
 
2 hours later…
ngn
9:30 AM
@DyalogAPL @ moon-child with ⊢ vs ⋄ the order of evaluation is different, though
 
Might have intended to say ((baz)⊣(bar)⊣(foo))
 
<moon-child> err, right; yeah
<moon-child> side effects are an illusion :)
 
10:05 AM
After the discussion around function definition syntax, I decided to write down my thoughts on the subject. Mostly so that I can gather my own thoughts on it. However, if anyone wants to read it and perhaps provide some helpful ideas, I would be very happy. I put it here: gist.github.com/lokedhs/72ce0a35dac6744c557a5a3fb18012aa
 
10:16 AM
Actually, this is a better link: write.as/loke/function-definition-syntax-in-kap
 
 
4 hours later…
2:39 PM
Does anyone know of an implementation of a Porter Stemmer in APL?
 
 
3 hours later…
5:45 PM
decided to do more performance testing on dzaima/BQN, and it turns out the tokenizer takes ~95% of complication time. ¯\_(ツ)_/¯
 
<loke[m]> The tokeniser? How can it be the main performance problem? What kind off magic does it do?
 
loke[m]: it's just complete garbage and has been for way, way too long
it takes an average of 131ns per character, but that's apparently way too high compared to the average of 2.1ns per character of compilation (complication obviously isn't per character, but still)
 
@dzaima use regex tokenizer
or wasm i guess?
 
@ASCII-only it's java. And I have much more that I could change before changing everything (checking if is valid name by 'a'<=c<='z'ish things instead of iterating through a list of chars, using a switch instead of many if-elses, etc)
 
6:00 PM
oh, java is just slow in general
 
@ASCII-only java is actually reasonably fast I've found
1.76ms → 1.63ms just by doing slightly less stupid stuff (though i feel like i'm still doing something incredibly stupid, and i should just rewrite it entirely anyways)
 
@dzaima ops.contains is slow
 
@ASCII-only right, but there aren't many better alternatives other than unrolling to a switch (which is still probably the right move). though hashset is still 1.56ms
 
@dzaima if it's APL unicode, they're all in a certain range aren't they
 
@ASCII-only it's the BQN charset, so things are all over the place
 
6:14 PM
:/
why not use unicode
 
@ASCII-only ?
it does use unicode (UTF16 because java but eh)
(and UTF16 is sort of annoying as BQN uses 𝕨𝕎𝕩𝕏𝕗𝔽𝕘𝔾𝕤𝕊𝕣 which are surrogate pairs in UTF16 (but this actually turns out nice for performance, as detecting them all is simply checking if the first char is 55349))
 
oh it has a different set of builtins
 
yeah
(and no, the horrific number parsing is apparently not a big issue, taking only ~2% of tokenization time)
@dzaima (marshall's tokenizer, written in BQN, executed by dzaima/BQN, is only ~2x slower than that, at 3ms)
 
6:31 PM
@dzaima Are you sure? Kap's tokeniser isn't slow and it's also using the JVM.
I'm not sure Java is to blame here.
@dzaima I have created a special kind of stream that works on codepoints (int's only). That way I have isolated the UTF-16 garbage to a single place. All code that deals with characters actually handles lists of integers.
Except for the formatting code, which deals with lists of strings (each string containing a grapheme cluster)
 
@EliasMårtenson how slow is your "isn't slow"?
 
@dzaima Not sure, but I'll be happy to measure. What should I measure?
 
@EliasMårtenson I've been measuring this file, and have an average of 120 ns/character now. Of course that specifically won't work for APL, but any sort of measurement of ns/char on a somewhat large file would be acceptable
@dzaima (my tokenizer definitely isn't slow slow, but it's still slow by at least some standards)
 
I don't have a file that big. What if I just creat a file of a few thousand lines and parse it?
 
@EliasMårtenson right, I kind of thought that'd be the case. do you have a separate tokenizer that could be fed some invalid KAP but valid APL for testing?
 
6:40 PM
Since you just want to test the tokeniser, it doesn't really matter what it is, right? I'll just assign some large arrays to some variables, OK?
 
problem with some manually created test is that it'd not be very respective of actual code. but i guess that's fine for an order of magnitude estimate
 
It took 0.007 seconds to tokenise, parse and run.
This is the Java version. Let me test the native version
The native version has previously been shown to be roughly 20 times slower than the JVM version.
 
@EliasMårtenson (i'm calculating the average of 100 runs, and do that some 5 times and take the best fwiw)
what's the :-stuff? (trying to translate to equivalent BQN)
 
I expanded the file (by copy/pasting) so that it's not 1508 lines liong. The JVM version now loads, compiles and runs it in 0.023 seconds.
 
@EliasMårtenson "not"?
 
6:48 PM
The native version gives me an error after 2 seconds. Seems like a bug in the native code. I'll look into that
I meant to say "now"
@dzaima They are symbols.
Performance-wise they should be equivalent to numbers.
 
i'd assume tokenization-wise they'd be more like strings, no?
 
Right. Performance-wise, they should tokenise like strings. But once tokenised, they are scalars, not arrays.
So yes, they should be harder on the tokeniser, but milder on the evaluation engine.
Interesting. In this particular case, the native version was only twice as slow as the JVM version.
It clearly depends highly on what the code is actually doing.
Anyway, the JVM version is always much faster than anything else.
 
@EliasMårtenson converted to dzaima/BQN (with strings in-place of symbols), after warming up with a couple thousand runs, tokenization+complication+evaluation takes an average of 5.4ms over 1000 runs
 
@dzaima And mine was 7 ms (one run only)
 
@EliasMårtenson yeah, how does that work (with no warmup, mine's 134ms ¯\_(ツ)_/¯)
@dzaima (that's around 4ms of tokenization and 0.7ms of compilation. Way bigger compilation overhead interestingly enough)
 
7:02 PM
I ran it several more times, and after a while it stabilises around 3 ms. The fastest being 2.something milliseconds.
@dzaima I don't have any split between tokenisation/compilation (they are not separate steps anyway).
I'd have to write some code to du measurement of the different stages.
But I think we're looking at the same order of magnitude at least, which would make sense, since I'm assuming that neither of our code is awful.
 
@EliasMårtenson um
@dzaima (it's also a bit more than a tokenizer - it groups parentheses, statements and strands too)
 
@dzaima I see what you mean. But based on my 20 second look at the code, I think even though it's not well structured (it's written as a quick hack initially, I presume?) it seems straightforward enough that performance-wise, I would expect it to be similar to mine, which indeed is what we saw.
Mine is also written in a similar straight-forward way, with very little in the way of triks to improve parsing performance (it wa snever a goal of mine).
 
how about this for a test:
https://dzaima.github.io/paste/#0VZpbduRADEIXpMMP@1/cpC0uqplkkk4/7LJKQoBsW5q/H/77ud8e/37P3y/J8/fj@/579PfU3zP@ff899O@d34f9/f@9TTz5@9j3pvkdWXn5O@h8v35vHO3n/o74@/899T3zLcEsy9/7Z5f1O/V3eJ7/HV27wP1jT/F93XK@tfzW9/2afSlXt0f9ff0@rVznfIv4PfwOP3t13zpnl/H7l3A0JJOLzVK@hX3H2GvOe7/YeqORsHhfsXbhG80v3vrevAtKiDZa4oAbi@8wysUnPt7PfsuaDei@J1u2Efle22DmtN@Zvnj9vvcU35Xtw0kIxXqHVFH2TzmTOM7sO7PD3gXuqbT/iMF3/ISYlCC45tC7wMl25yibczMkrPbMc9ufDP9yZrLASei/AysHJstaCok1oWhUN@KJ1ZdNu6smrffJTSa7V7lrJbiTFexaknzfmVIXCdOm1he85JWSS4nALpJk8lBtm5fag@d0dvZ0U9nkiLf4JjuTh2RxwrF1P@TbZnVOtHvrbCzZm70ILuw2bDYqi
 
I can't really copy it from there.
Can you make it into a gist or something so I can copy it as raw text?
 
@EliasMårtenson click the edit button
@dzaima (yeah, browser really doesn't like selecting text spanning many spans)
 
7:14 PM
Sorry, that causes my parser to error out with a stack overflow.
Let me try with a bigger stack
 
@dzaima (with my local changes, takes an average of 3.1ms - 0.56ms tokenization, 2.1ms compilation (times swapped now :o), 0.2ms execution (yes those don't add up, i'm timing each separately))
 
@dzaima How much of the time for the BQN-based tokenizer is used by the in CharCode? Also note that Tokenize deduplicates tokens, which is probably a decent fraction of the total time. If you switch the character code lookups to Java, it might make sense to do a lot of the tokenization array-style, since it takes advantage of booleans.
 
@dzaima Yeah, Kap didn't like that one at all. It blows the stack, which is an artefact of the way parsing is done left-to-right.
In practice it's not really an issue, but it runs into trouble in cases like that one.
The solution would be to manage the parse stack separately, and not use he Java stack, but that's for a later project :-)
Time to sleep now anyway. Thanks for an discussion which was interesting enough to keep me up until 03:20
 
@Marshall 0.47/2.79ms
 
@dzaima Not actually that bad then. On reflection, the array-style tokenization might be better for some things like word (number or identifier) detection, but those are probably a small portion of overall time, so it's not really worth it. Unless you have a huge codebase and can switch the whole thing to GPUs or something like that.
 
7:27 PM
commenting out everything after # Deduplicate literals and identifiers gives 1.95ms
 
@dzaima What about ReadNums?
 
@Marshall just commenting out the num← line?
 
@dzaima Maybe replace ReadNums with @, since the rest of that line is part of the tokenization.
 
actually i can just •_PFC_"ReadNums" it; takes 0.2/2.75ms
 
@dzaima So ~100ns per number. Better than I expected.
 
7:36 PM
all of the "Extract words" section takes 1.24ms/2.76ms, "Extract character and string literals" takes 0.42ms
 
@dzaima Is that counting CharCode and ReadNums? I don't see anything obviously expensive in "Extract words".
 
@Marshall it is
 
@dzaima Okay, so 0.5-0.6ms for the rest of it. That sounds about right.
 
the "Resolve comments and strings" takes .45ms/2.7ms
 
No real bottlenecks, so basically the whole thing is just a few times slower than a good Java implementation with the current runtime.
Which is fine. It's way better than the average interpreted language could do. It would be a pretty big stretch to say it's the future of compilation though.
 
7:49 PM
@dzaima (i'm still kind of puzzled by that compilation speed difference - 2ns/char vs 200ns/char is pretty big regardless of difference in source)
 
8:32 PM
is anyone else doing genuary2021? -- i am
 
8:50 PM
@dzaima got it down to 1.2ms compilation by doing manual parsing instead of the string pattern matching for monadic/dyadic function application
@dzaima not that much of a difference outside of that example - on Marshall's compiler, 0.022→0.020ms, but that's within the realm of error and i can't be bothered to check more thoroughly
 
9:04 PM
interestingly enough, this function appears to take 7.8% of time of compilation (of c.bqn)
@dzaima (yay i actually finally started profiling things)
oh, you know what, i'm stupid. Tokenization of a string involves compilation all inner block and compilation of the tokenization result only involves compiling the outermost part of it. So my separation of tokenization and compilation is extremely wrong
 
CMC: given a rule in any format and a previous row, return the next row of an elementary cellular automaton
 
@Wezl Does this mean 3-neighbourhoods?
 
I just did this here, and I'd like to see other's versions
@Adám yes
 
9:20 PM
@Wezl ⌺3
(takes rule as function operand)
 
without stencil? (because I don't understand it)
 
I'd rather explain it then.
 
@Wezl {(⍎⍺)⍵}, take rule format as a string representation of a transformation function :)
 
Stencil simply applies the left operand (a function) to each neighbourhood of size right-operand.
 
@Adám can you convert a wolfram code to that function?
 
9:24 PM
@Wezl Extremely easy. WOrking on it.
 
@dzaima I should have specified an input format :arg:
 
@Wezl {(⌽⍺⍺⊤⍨8⍴2)[2⊥⍵]} so e.g. 110 is 110{(⌽⍺⍺⊤⍨8⍴2)[2⊥⍵]}⌺3 using ⎕IO←0
 
now I'll call that a complete solution
 
If instead we take the rule number in reverse binary, we can use 0 1 1 1 0 1 1 0{⍺⍺⌷⍨2⊥⍵}⌺3.
 
ngn
9:40 PM
@Wezl short or fast?
 
short
 
10:16 PM
@DyalogAPL bridges from a channel on irc, right?
 
@Wezl yeah, freenode #apl
 
ngn
@Wezl based on adam's: {2|⌊⍺⍺÷2*2⊥⍵}⌺3. without stencil it can be something like ..2⊥¨3,/0,0,⍨⊢
 
@dzaima (and there's a bridge between matrix and IRC too - the users with [m] at the end of their name)
 
<wezl[m]> okay, sorry people, this is a test
 
@dzaima (and then there's a bridge from here to matrix that i'm working on, so the above message went through 3 bridges to arrive at my local matrix homeserver :D)
 
10:22 PM
<wezl[m]> @Wezl I've never been able to ping myself before
 
@Wezl See how to here.
 
or here
 
I mean without replying
 
11:24 PM
is n+/ special cased?
 
@rak1507 Yes.
@rak1507 In general, you can check if something is special-cased byt making a trivial modification and comparing performance:
      ]runtime -c +/?⍨1000 +∘⊢/?⍨1000

  +/?⍨1000   → 1.3E¯5 |    0% ⎕⎕⎕⎕⎕
  +∘⊢/?⍨1000 → 1.1E¯4 | +726% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
 
Ah yeah
 
11:49 PM
The behaviour of 0+/ is quite interesting
 
Do you understand why it has to be that way?
 
Well it seems like (≢n+/a) ≡ (1+n-⍨≢a) so 0+/a is logically (1+≢a)⍴0
But I can't see a reason why it's that way intuitively
 
How about locating all starting positions of subvectors of length 0?
 1 2 3
^ ^ ^ ^
 
Ah, makes sense
 
'tis so for regex too…
⋄ ''⎕S'&'⊢'123'
 
11:54 PM
@Adám
┌→────────────────┐
│ ┌⊖┐ ┌⊖┐ ┌⊖┐ ┌⊖┐ │
│ │ │ │ │ │ │ │ │ │
│ └─┘ └─┘ └─┘ └─┘ │
└∊────────────────┘
 
Interesting
 

« first day (1438 days earlier)      last day (1217 days later) »