12:11 AM
does anyone remember what `int monad/ints` meant in k3?
there's a question in matrix chat about the meaning of `j v/i` and "chase pointer" here

12:28 AM
q)3 {x+1}/ 1 2 3
4 5 6
I don't know abut k3, but in Q, it apply f x times to y.

@HaoDeng but the comment on nsl says "starting at index j"

Like I said, I have no experience or access to k3.

12:46 AM
@ngn i believe the "chase" means this
"j" would be a distinct starting index

@Traws i think understand the monadic case, but the dyadic is still a mystery to me
if j is the starting index, then what is i?

too bad we don't have an example of the j case to reverse engineer it

might be a mistake

1:17 AM
@ngn it seems so.. the natural extension would be to keep indexing j times and that's what k7 does

yeah, it does that in all ks i'm aware of (with somewhat different syntax in k9)
(if we ignore base-encode/decode overloads)

the overloads are much better
but it kinda hides the lists are functions paradigm

@coltim i think i managed to vectorize find :) no intrinsics

1:42 AM
finding a needle in a hay stack.
Algorithm A: go straw by straw and test if it's a needle
Algorithm B: this time you have a metal detector. you grab a bunch of straws and test if there are any needles there. if there aren't - discard it and grab the next bunch. if there are, start looking for the needle in the bunch using algorithm A

Applying Algorithm B hierarchically gives a B-tree :P

2:07 AM
an algorithm-b tree, surely

6 hours later…
7:58 AM
What is the best way in ngn/k to pad two strings to be equal length?
Spaces as padding char is ok

pad to the left or to the right?

Right
I mean pad each max length x,y is one way, but now that flip is gone, is there another way?

Maybe something in the line of `((#x)|#y)\$(x;y)` i.e. just pad manually, but `\$` works on list of strings right arg

@Bubbler oh interesting, I didn't know that about pad

Me too. I just thought "padding would be sensible to apply to each string in y" and tried it out, and it did work

8:10 AM
Makes me wonder if pad could take a fn on the left to avoid repeating
`(|/#')\$`
Given it is designed to take lists of lists

Is there a neat way to find the location largest element of a list (i.e *>), but if there are several instances of the largest element, return a list of locations? I got to `{&x=|/x}` -- is that the way?

I think that's the right way

Could do `:/=` in k9 since group sorts

8:30 AM
What does `*|<="racecar"` give you in ngn/k
(Sorry, can't test myself right now)

`"e"`

Ah well

`<dict` is sort keys by values, and (unsurprisingly) the largest value is always the last one, so...

@Bubbler I get mixed up on how the grades work between k dialects

understandable

1 hour later…
9:42 AM
Anyone golf this down? Find the (possibly several) most frequent items in a list: `{(!t){&x=|/x}@.#'t:=x}`

@xpqz {&d=|/d:#'=x}

would be nice if f#x worked on dicts `{x=|/x}##'=:`

@rak1507 good idea

CMC: `{x=|/x} golfed`

`=/|/\`

9:50 AM
yep

assuming input is simple list

well that was boring

@ngn wow, k dicts rock

@Bubbler but no bytes saved when used as a left arg

a possible alternative approach to the projections problem, if anyone wants to have a crack
idea being to convert the input lists into occupied slots or unoccupied slots (`;`), then expand and merge
not sure how you'd get the input lists into the appropriate form or if the approach generalises correctly
but at least it avoids splitting on `;`

10:04 AM
I am blown away by the utility of being able to do this:
```&`a`b`c`d!0 1 0 1
`b`d```
@ngn I think this should be in your repl's \+ under &d, unless I just can't see it.

10:20 AM
can't give away all the secrets! takes away the fun of discovering them...

Someone clearly thought through how dicts should work in an array-y language.

11:00 AM
@JohnE it's unfriendly companies that copyleft licenses help with. With a permissive license, a company could just take your array language, put a couple thousand man hours into optimizing it, and sell it as a 2x faster version. Then they're gaining money directly from not contributing to intellectual commons!
good people/companies won't have trouble sharing their modified source. Bad people will do bad things regardless of anything. As such, bad companies are the only ones hurt by copyleft

2 hours later…
12:36 PM
@xpqz the part that clicked for me was that operations that either take or return indices (when working on e.g. a simple list) instead work on the dictionary's keys. this includes things like `&x`, `<x`, `>x`, `x@y`, `x?y`, `=x`, `x_i` (there may be others...)
@dzaima I think it's more that the companies that are hurt are the ones with conservative legal teams that would rather not deal with copyleft licenses at all

12:59 PM
@coltim eh, true. But those wouldn't share the source if given a permissive license anyways

@coltim I was pleased with my 1 byte saving going from `{x[<#'x]}` to `{<x!#'x}` by dictifying
@dzaima Well, working for a big multi-megacorp, we're certainly very dilligent with sharing back everything we change or fix in a huge range of OSS projects with permissive licenses. We also have an outright ban on anything xGPLx.

huh.

The other megacorps though.... :)

@ngn how does ngn/k deal with overloads in the source? I can't read it very easily atm.. so not sure

@xpqz now help me convince ngn to make `(f)!` `{y!x y}`

1:13 PM
@dzaima If I was building a database, an in-memory cache layer or distributed full-text search engine (picking some examples at complete random), I'd think extremely carefully about licenses before a hyper scaler picked it up 'as a service'.
@chrispsn what does that mean?

overload f!x so f!x is x!f x

Ah, I see. Like python's `{k:f(k) for k in x}`?

that would be f' but yes
(at least, I think, there's probably some debate as to whether it should be x!f x or x!f'x like there was for #...)

@rak1507 which part do you mean? like how the code is structured, how the determination of which overload to apply is made, etc etc

@coltim both, was wondering if I wanted to add in an overload for f#d for example, how would I do that

1:22 PM
@rak1507 hmm. as far as I can tell, the overloads are sometimes within the same C function, and sometimes split out into separate ones. I assume that the determination of which overload is done with all the helper macros that examine the type of the input
@rak1507 otherwise I would track down the commits where the overload was added/modified =|

@coltim ok, that's what I guessed
'helper macros' - what I didn't want to hear

this commit is where `f_x` was added. I assume if you are able to implement your tweak in K you can insert it somewhere as a K-string

thanks
CMC: golf `{x@<x?x}`
(sort by first occurrence)

1:58 PM

@coltim clever.

@xpqz it's a part of @chrispsn's "ungroup-dict" implementation: `{(&#'x)@<,/x}`
(and @ktye's too!)
@ngn on @Traws' example it's now ~7% faster on my machine, although the ASM looks like an unrolled for loop rather than SIMD stuff
one way to SIMD it would be to do something like `idx += tzcnt(movemask(cmp_eq(load(chunk), lookup)))`, maybe unrolled a bit
(but I would be surprised if a compiler would transform it to that =|)

2:36 PM
I get an unrolled loop too:
https://dzaima.github.io/paste/#0tVfdbtowFL7nKVxVqmJwgx0CDdBsatVNQ0K06lCrlaEpJA64hRAIQ@nW3e6@2hvuSeb8EEIIgU5gyYL4@JzvOz85HMyGAEFxMB7RovFDYyOt2Gez4lPxKfdhTq1ZDejP@pA6udwNner8AIQrB1ZX9vMVczTHoaPe8BmMTeBQfcbGFhBn1J3VslVxbBkVDYNzs/EuoWNyJ2q78Dg2qMksCgZCG35dFbUaoAnM4@O2cH2Xt1HLQs05/CZcg3ZeU200Uef1G2F@Onl5ObJQqwkbTMWorz5cFD8/CHkNIlPF9XuBnVsnJ0cmehT6yHxRtQ4rFLqqOoGQnar9und8KfBT/4zLIFd4z2rc4DqfO/BxyWeE2l8E8xKaiD9PfH75KfwZ8JvUmWChqWfWFGw0Qh4ChL9SfbQ9oxfcZht4Hl64at6utyzVtepNpvohcO@QheaQe8zOMcrbqmbPBRed8CMLMrhqdSBcwoHwie8G302YTAG1jN60Im@qlBl1/KqaOgzxvSr@@/sPeKTBd4JLafqj8dxx
for that matter, + doesn't look too good either:
https://dzaima.github.io/paste/#0lVjdbqNGFL7PUyBZqsCesDMw2JCsI7VK1Uba7KZbS6vWciUM44TUNgQcl1R7vfdV37BP0vkBe4AZnHABeOb8fHO@c84w/nFPtrsLI3qJ1qQ4O7sjeUQHjOo6M5pX/@/rpAiLgmyW6xcjXRkFiXZJujXsHSl3F/2q8Hg5HsbQeB/e3Fy1lOiQaV0otAcxWSVbYjx8MldgBtbgHhDbti3jYcUHbsw1@PDRDC3rQzKFl1/M5P0WkMtH8x7k88fFdE9vVjKa3l@Go@l6eH@5ZO85vVmJZbx7VzxnWZrvjHRP8tU6/avQuP@@dm@JCQnPzNjP7xfcJfM2Defr4eNitGSeZ0ZKUbGp9OvUFDN/cEzfmUxAvFt3Znp19evv5swa@ucIJJalgXHbA2MwcJRIhiabsjgeNnVnsslz6ow9mTOdt9TcgZl1nKBRCAeD3WAwoz4h@IkBtsTgTAyievDW3HQl@WBLUuN623b9seF6ZImBgzE@ILscVgMHiWHLFV3dEvxg0cc

2:55 PM
oh, apparently I need to explicitly `make CC=clang`

wasm simd when

yeah, with that things actually look right:
@dzaima actually, that `+` still has 52 instructions for the 8 packed additions, which is way too much
it appears to be both reading and writing the items one-by-one..
lol CBQNs unvectorized `+` is a bit faster than ngn/k's :D

3:16 PM
@xpqz this is precisely my experience in the corporate world. In another field I intersect with, video games, GPLed libraries are also poison; the linking/distribution requirements are often hard or impossible to satisfy when distributing games for many platforms. This isn't just hurting greedy corporations, either- independent creators with shoestring budgets are hurt far more, and they often find themselves forced to use commercial products instead of open-source alternatives

3:37 PM
@dzaima ah, that does it for me too. clang is much better at autovectorization than gcc. now getting >2x performance

@JohnE the whole static/dynamic linking thing is pretty stupid, yeah. unfortunately defining what's a modification and what's usage is pretty hard.

@dzaima you could try using i64's (your example uses i32's) with something like `a:100000?0`. it's ~2x as fast for me locally. I assume the 32bit version is doing all that stuff in order to handle overloads
(the ASM looks much more like one would expect as well)

the CBQN example is using `i32`s too, and has to check for overflow just like ngn/k
of course i64 code is gonna be simpler
https://dzaima.github.io/paste/#0nZhtj5s4EIC/769AinSCxCWYt8Bus9JFW91V6rarXqSqt8pJBpyEbRI4ICm7us/9XvUf9pecjSE45KUGpARiz8zjscczwWgykRVpuIzWeBi8oHCNhoswG34Zfrl6s8Ob7Fryn/0VTq@uHnDikwapvK6kw@vy77swRWmK197qWYrmUor9LIw2kprhPLu@rKrtL1MfIaxJr9FkcttQQtSN6xPavQDPww2Wlh/kOZiCFVgArKqqIi3nRcNbeQXevZeRorwLx9rNJzl8vQH45klegOTxaTbekS8lHIwXN2gwXvUXNx59TsiXEpJ5G6bbOI6STIp2OJmvoq/pGfzvFV5hHdx4ptLucTErkJQ2Ro@r/tNs4FHyVIrIqGhX9N9YZj3/FGP6TaYC7Fl5kKPb27/@lqdK33kFQagoZ4Zxf2EYvZ5@ciR9mXYpxXho14NMO18RGL1T2DlaJGdgqtQdZBZQr5f1elPC1MAfdMAKa5yyRlg13svrY8misSF5Br1pot8foAcKa9gbKxp4ZL9s2Ev0GyjinQcmCrktwZ

I wonder what the best way to SIMD-implement overflow logic would be. upscale each chunk to the next integer size, do the addition, check if it's larger/smaller than INT_MAX/INT_MIN, and if it is, punt to the error handling logic?

the upscaling is probably gonna make it not worth it. `((x^res) & (y^res)) < 0` is probably the best way
in The APL Orchard, Jan 20 at 20:42, by Marshall
@dzaima Ah, I thought I remembered having to do the bitwise version for something. I feel like I got it an instruction or so better than `((w^r)&(x^r)) < 0`, but I don't remember how.

1 hour later…
5:07 PM
@coltim yep

Here are my solutions to the 2016 competition if anyone wants to golf/laugh: gist.github.com/xpqz/d055cb2668e2e10ea496b39ce7b47354
Number 2 was the stand-out poor solution.

6:12 PM
@xpqz this golf has some clever tricks. it can be adapted/golfed in ngn/k as ngn.codeberg.page/k/…
(the median of an empty list (I think that's what ⍬ represents?) being 0 is a bit odd. these return `0n`, a floating point NaN, instead)

6:29 PM
@xpqz #7 could be `(~&/3 5!\:)#`. regardless, `0=` can be replaced with `~ not`
#8 could use a dictionary/group approach: `{.|x@=x<0}`, although what you have is quite nice

6:45 PM
#5 may need a trailing `:` to ensure the `=` is `group` and not `equals`
and #9 may need to be `{x\y}` (`/` and \ always parse weirdly =|)

1 hour later…
7:46 PM
@coltim @ngn another datapoint from that example.. previously: (gcc) 10s, now: (gcc) 7.5s, (clang) 3s, (gcc+small domain trick) 0.09s, (clang+sdt) 0.08s
@coltim @xpqz it could be (|/~3 5!\:)# aswell, maintaining the original logic

4 hours later…
11:36 PM
@ngn `>'1` exits the repl