Well, I was using my right hand/ lh/ 2 fingers & thumb, a la Faraday, for 
insight!  
Didn’t help!
Mike

Sent from my iPad

> On 10 Jan 2022, at 04:54, Raul Miller <rauldmil...@gmail.com> wrote:
> 
> I should perhaps clarify -- since there's no actual physical
> coordinates involved here. I am using "left handed" and "right handed"
> to refer to what should maybe be labeled as the parity of the axes of
> the coordinate system.
> 
> I really need better vocabulary for talking about these distinctions.
> 
> Thanks,
> 
> -- 
> Raul
> 
>> On Sun, Jan 9, 2022 at 11:52 PM Raul Miller <rauldmil...@gmail.com> wrote:
>> 
>> Also, ... I believe that that cross product is a right handed cross
>> product. It would be interesting to think about what would need to
>> change to make a left handed cross product work (for example, the
>> cross product implementation in the complete tensor essay in the
>> wiki).
>> 
>> (I had thought that I was agnostic to the handedness of the coordinate
>> system, but it looks like that was not the case.)
>> 
>> (A trivial fix would be to negate all beacon coordinates along one
>> axis. But I am wondering if there is a simple algorithmic fix which
>> would retain the original coordinate values...)
>> 
>> Thanks again,
>> 
>> --
>> Raul
>> 
>>> On Sun, Jan 9, 2022 at 8:36 PM Raul Miller <rauldmil...@gmail.com> wrote:
>>> 
>>> 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
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to