Oops, I thought I had included that in my message. My apologies:

NB. from https://code.jsoftware.com/wiki/Phrases/Matrices
cross=:(1 _1 1 * 1 (-/ . *)\. ])@,.

Good question, thanks.

-- 
Raul

On Sun, Jan 9, 2022 at 9:49 AM 'Michael Day' via Programming
<programm...@jsoftware.com> wrote:
>
> Raul,  would you mind defining cross?  I've tried */ and (+/  .  *) but
> neither seem to
> work for me,  and I'm not sure what you mean.
>
> As I said a few days ago,  I gave up wondering why I'd found 48
> rotations when they
> asked for 24,  couldn't grasp what the meant by facing" and resorted to
> matrix divide
> with rounding to yield the orientation matrix in each case.
>
> Still stuck on day23 part 1!!!
>
> Cheers,
>
> Mike
>
> On 09/01/2022 02:14, Raul Miller wrote:
> > https://adventofcode.com/2021/day/19
> >
> > Like a variety of my work on previous days, my code here is rather
> > bulky. Did I mention that Advent of Code was something of a bad habit
> > for me?
> >
> > Anyways, here, not only is the code bulky, even the sample data is bulky.
> >
> > Basically, for this puzzle, we were given a bunch of coordinates
> > beacons reported by a small set of scanners. These coordinates
> > contained three "flaws":
> >
> > (1) They used a coordinate system which was centered on the scanner --
> > not a universal coordinate system.
> >
> > (2) Each scanner had limited range, so no single scan had locations
> > for all beacons.
> >
> > (3) Each scanner had an undetermined orientation.
> >
> > Luckily for us, each probe "originally" had the same coordinate
> > system, and each probe's rotations were multiples of 90 degrees along
> > each axis. So there were only 24 possible orientations for each
> > scanner.
> >
> > And, sample data looked like this:
> >
> > sample=:{{)n
> > --- scanner 0 ---
> > 404,-588,-901
> > 528,-643,409
> > -838,591,734
> > 390,-675,-793
> > -537,-823,-458
> > -485,-357,347
> > -345,-311,381
> > -661,-816,-575
> > -876,649,763
> > -618,-824,-621
> > 553,345,-567
> > 474,580,667
> > -447,-329,318
> > -584,868,-557
> > 544,-627,-890
> > 564,392,-477
> > 455,729,728
> > -892,524,684
> > -689,845,-530
> > 423,-701,434
> > 7,-33,-71
> > 630,319,-379
> > 443,580,662
> > -789,900,-551
> > 459,-707,401
> >
> > --- scanner 1 ---
> > 686,422,578
> > 605,423,415
> > 515,917,-361
> > -336,658,858
> > 95,138,22
> > -476,619,847
> > -340,-569,-846
> > 567,-361,727
> > -460,603,-452
> > 669,-402,600
> > 729,430,532
> > -500,-761,534
> > -322,571,750
> > -466,-666,-811
> > -429,-592,574
> > -355,545,-477
> > 703,-491,-529
> > -328,-685,520
> > 413,935,-424
> > -391,539,-444
> > 586,-435,557
> > -364,-763,-893
> > 807,-499,-711
> > 755,-354,-619
> > 553,889,-390
> >
> > --- scanner 2 ---
> > 649,640,665
> > 682,-795,504
> > -784,533,-524
> > -644,584,-595
> > -588,-843,648
> > -30,6,44
> > -674,560,763
> > 500,723,-460
> > 609,671,-379
> > -555,-800,653
> > -675,-892,-343
> > 697,-426,-610
> > 578,704,681
> > 493,664,-388
> > -671,-858,530
> > -667,343,800
> > 571,-461,-707
> > -138,-166,112
> > -889,563,-600
> > 646,-828,498
> > 640,759,510
> > -630,509,768
> > -681,-892,-333
> > 673,-379,-804
> > -742,-814,-386
> > 577,-820,562
> >
> > --- scanner 3 ---
> > -589,542,597
> > 605,-692,669
> > -500,565,-823
> > -660,373,557
> > -458,-679,-417
> > -488,449,543
> > -626,468,-788
> > 338,-750,-386
> > 528,-832,-391
> > 562,-778,733
> > -938,-730,414
> > 543,643,-506
> > -524,371,-870
> > 407,773,750
> > -104,29,83
> > 378,-903,-323
> > -778,-728,485
> > 426,699,580
> > -438,-605,-362
> > -469,-447,-387
> > 509,732,623
> > 647,635,-688
> > -868,-804,481
> > 614,-800,639
> > 595,780,-596
> >
> > --- scanner 4 ---
> > 727,592,562
> > -293,-554,779
> > 441,611,-461
> > -714,465,-776
> > -743,427,-804
> > -660,-479,-426
> > 832,-632,460
> > 927,-485,-438
> > 408,393,-506
> > 466,436,-512
> > 110,16,151
> > -258,-428,682
> > -393,719,612
> > -211,-452,876
> > 808,-476,-593
> > -575,615,604
> > -485,667,467
> > -680,325,-822
> > -627,-443,-432
> > 872,-547,-609
> > 833,512,582
> > 807,604,487
> > 839,-516,451
> > 891,-625,532
> > -652,-548,-490
> > 30,-46,-14
> > }}
> >
> > There will be a quiz later.  (Ok, maybe not...)
> >
> > So, first thing we need here is a mechanism to parse this into
> > something J can handle. And, it's not obvious here, but the number of
> > beacons reported by each scanner was not the same. This means we need
> > to put the scans in boxes so they are not padded.
> >
> > I decided I also wanted my parsing routine (which I named 'get') to be
> > idempotent. This would let me use parsed or unparsed data on the
> > command line -- if it was parsed already, 'get' would leave it alone.
> >
> > get=: {{
> >     if. -.'literal'-:datatype y do. y return. end.
> >     s=. getscan;._2 rplc&(',';' ';(LF,'---');LF,'!---') y,'!'
> >     {:"1 s   assert. (i.#s) -: ;{."1 s
> > }}
> >
> > digits=: ".@([ -. -.)&(~.":i.10)
> >
> > getscan=: {{
> >    (id=. digits 0{::lines); coords=. __&".@>@}. lines=. (<;._2 y)-.a:
> > }}
> >
> > I could have made get and getscan a little simpler, by ignoring the
> > reported scan number. But I was working on this puzzle late at night
> > and it was easy for me to make mistakes.
> >
> > The next problem was to piece scans together to form the complete list
> > of beacons (using the coordinate system of the scanner #0).
> >
> > There's a variety of approaches which could have been used here. Mine was 
> > this:
> >
> > (a) I would measure the distance between each pair of *beacons*
> > reported by each scanner. The distance between any beacon pair was
> > guaranteed to be fixed for every scanner which included both of those
> > beacons.
> >
> > (b) For each pair of *scanners*, I would find and count the beacon
> > distance lists which they had in common. Scanners which were closer
> > together should have more beacons in common with each other than
> > scanners which were farther apart.
> >
> > Looking at the data, I saw that most scanners had at least one other
> > scanner which reported 67 or 68 of the same beacon distances, the next
> > most frequent commonality was 17 or 18 of the same beacon distances.
> > So, in code, I only concerned myself with scanners which had at least
> > half as many beacons in common as the largest reported commonality.
> >
> > (c) For these pairs, I would find the orientation of the second based
> > on the orientation of the first, using the beacons which they had in
> > common (the ones whose distances were the in each of the pair of
> > scans).
> >
> > In particular, I decided that I could ignore two problems:
> >
> > (*) I was not concerned with "spoofed distances". I had enough
> > information that I believed that coincidental distance matches would
> > not be a problem for me.
> >
> > (*) I was not concerned with "spoofed orientations". I had enough
> > information that I believed that there would be one and only one
> > orientation that best fit the beacons for the scanner pairs I was
> > considering.
> >
> > That left me with the problem of representing intermediate results.
> >
> > The first step -- getting distance pairs between beacons reported by a
> > single scanner -- was straightforward:
> >
> > signature=:{{+/&.:*: |:-"1/~ y}}
> >
> >     usigs=: ~.@,@signature each scans
> >     rough=:  +/@(e.,)&>/~ usigs
> >
> > The next step - identifying pairs of scanners which were close to each
> > other - had one minor trick: each scanner was very, very close to
> > itself. And I needed to ignore that.
> >
> > In other words, I multiplied by the logical negation of the identity matrix
> >
> >     rough=:  (* -.@=@i.@#)+/@(e.,)&>/~ usigs
> >
> > Actually, though, I did not need the counts of close beacons -- I just
> > wanted to identify the scanners which had a lot of beacons in common
> >
> >     rough=: (> -:@(>./)@,) (* -.@=@i.@#)+/@(e.,)&>/~ usigs
> >
> > Next, I wanted to visit those pairs in sequence, starting from scanner
> > zero. There's a variety of ways of doing this, but one way is to use
> > rough as a connection matrix. Then (+./ .*.)&rough given a selection
> > mask would lead us to the connected scanners. These connections are
> > bidirectional, and we want to know how soon we can visit a scanner. We
> > can use ^: to iterate some number of times and then </\ to find the
> > first 1 in each column. My approach here included a lot of extra blank
> > rows, which I suppressed using ~.
> >
> >     ~.</\(+./ .*)&rough^:(i.#rough) (#rough){.1
> >
> > Finally, I can't sort on a list of bitmasks, but I can convert them to
> > an ordered list of indices that represent the order I want to visit
> > the scanners.
> >
> >     order=: ;<@I. ~.</\(+./ .*)&rough^:(i.#rough) (#rough){.1
> >
> > I'm not quite ready to compare scanner pairs yet, though -- I need to
> > extract the "close scanner pair" list from rough, and sort them:
> >
> >     close=: (/: order&i.) ($#:I.@,)rough
> >
> > But that approach actually lists each scanner pair twice (0 7 and 7
> > 0), and that's not necessary. So, I could do:
> >
> >     close=: ~. /:~"1 (/: order&i.) ($#:I.@,)rough
> >
> > or
> >
> >     close=: (/: order&i.) ($#:I.@,) (* </~@i.@#)rough
> >
> > With that setup, I am *almost* ready to walk through my scanner pairs.
> > But I still need to represent their orientation and offset.
> >
> > Each scanner has both an offset from the global origin (scanner 0),
> > and an orientation with respect to scanner 0. The offset is easy to
> > represent -- that's just an x,y,z value. The orientation, though, ...
> > that I represented as a permutation of the axis along with a sign
> > (positive or negative) for each axis.
> >
> > reorient=:{{
> >    's a'=.8 6#:{.x
> >    off=. }.4{.x
> >    sign=. _1^2 2 2#:s
> >    off+"1 sign*"1 (a A. i.3) {"1 y
> > }}
> >
> > Here, x is the orientation and offset for the scanner, and y is the
> > list of beacon coordinates to be manipulated.
> >
> > This is not an optimal representation. The problem with this approach
> > is that it can represent both right handed and left handed coordinate
> > systems, and I only wanted coordinate systems which could result from
> > a rotation of the origin coordinate system.
> >
> > I did not know whether that origin system was right handed or left
> > handed (since I didn't have any external reference data), all I cared
> > was that my alternate orientations matched. To solve this I did a dry
> > run, using an identity matrix in place of beacon coordinates, and 0
> > offsets. If a cross product of the first two result coordinates
> > matched the third, I had a viable orientation:
> >
> > plausible=: I.({:-:cross/@{.~&2)@reorient&(=i.3)"1 ,.i.48
> >
> > Still with me? I got to this point mostly by trial and error, with
> > lots of asserts in my code to make me aware of invalid assumptions.  I
> > have since deleted most of those mistakes and the assertions which
> > made me aware of those problems. And, I've cleaned up some of my code
> > a bit from my initial puzzle solution, so that it would be readable.
> > But I am not sure how well I am explaining my resultant
> > understanding...
> >
> > The next stage of puzzle solving was, for each pair of scans:
> >
> > (1) find the beacon coordinate pairs in each which share a distance
> > between the scanner pair.
> >
> > (2) Try each of the plausible orientations (with zero offsets),
> > subtracting the selected parts of the scanner set. Since the beacon
> > coordinate pairs are ordered by distance between the pair, they are
> > ordered the same for each scanner set. And, when I get the orientation
> > right, distance between pairs from the two sets will mostly be the
> > same distance apart (this will be the distance between the two
> > scanners).
> >
> > My implementation is still a bit sloppy here, but it gets the job done:
> >
> > whichori=:{{
> >    d=. #@~.@:(-&x)@reorient&y"1,.plausible
> >    plausible{~d i.<./d
> > }}
> >
> > relori=: {{
> >    'c0 c1'=. y
> >    sigs=. signature@>y
> >    k=. +/4=#/.~,sigs
> >    ref=. k{.}. (~. \: #/.~),sigs
> >    ids=. (* k&>) ref i. sigs
> >    pairs0=. pairs1=. i.0 0
> >    for_id. 1+i.k-1 do.
> >      j=. (}.$sigs)#:I.,id=ids
> >      assert.4=#j
> >      pairs0=. pairs0,(2{.j) { c0
> >      pairs1=. pairs1,(2}.j) { c1
> >    end.
> >    o=. pairs0 whichori pairs1
> >    candidates=./:~(#/.~,.~.),/pairs0 -"1 o reorient pairs1
> >    assert. ~:_2{.{."1 candidates
> >    off=.}.{:candidates
> >    o,off
> > }}
> >
> > Note that when I wrote this code I was not completely sure that I
> > would not have "spoofed distances". So I am not actually completely
> > ignoring that problem -- the assert. 4=#j in the middle of relori
> > would fail if I somehow had the same distance between more than a pair
> > of beacons. (It's 4, rather than 2, because each pairing is
> > represented twice -- I found the distance between each pair of beacons
> > and beaconA is the same distance from beaconB that beaconB is from
> > beaconA.)
> >
> > It would be fun working out how to express this more concisely, but I
> > haven't thought enough about that issue.
> >
> > And, that's all the pieces I needed for part A, which was to count the
> > total number of scanned beacons:
> >
> > a19=:{{
> >     scans=: get y
> >     heritage=:(,;0);(<:#scans)#<i.0 0
> >     usigs=: ~.@,@signature each scans
> >     rough=: (> -:@(>./)@,) (* -.@=@i.@#)+/@(e.,)&>/~ usigs
> >     order=: ;<@I. ~.</\(+./ .*)&rough^:(i.#rough) (#rough){.1
> >     close=: ~. /:~"1 (/: order&i.) ($#:I.@,)rough
> >     known=:,:0 0 0 0 0
> >     for_scanpair.close do.
> >         'kid jid'=. scanpair /: (0,,scanpair_index{.close) i. scanpair
> >         kori=. }.(({."1 known) i.kid){known
> >         known=: known,jid,t=.relori (kori reorient kid{::scans); jid{::scans
> >    end.
> >    #~.>,each/(}."1/:~~.known) reorient L:0"_1 scans
> > }}
> >
> > I've left a variety of global assignments here, because looking at
> > example data really helps when understanding the code. Also
> >
> > For part B, the problem was to find the largest "manhattan distance"
> > between two scanners.
> >
> > In other words, given the location of each scanner
> >     2}."1~.known
> >
> > take the sum of the absolute values of the difference between each
> > pair of locations, then find the largest of those sums
> >
> > b19=:{{
> >    a19 y
> >    >./,+/"1|-"1/~2}."1~.known
> > }}
> >
> > If there's something here which I should have explained better, and
> > you can think of a way to phrase a question about it, let me know...
> >
> > Thanks,
> >
>
>
> --
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to