hp
toc

Advent of Code 2024: A little past halftime.

2024-12-19, post № 293

advent-of-code, #coding, #lang:Go, #lang:C, #lang:Haskell, #lang:Shell, #lang:Ivy, #maze, #SSA

Twenty twenty-four is the first year I actively participate in Advent of Code: Each day, I open my digital advent calendar’s door and brood over how best to help the Christmas Elves find their Chief Historian. Although I had heard of Advent of Code and a fellow student had once bothered me two years past with aoc/2022/16/1, where I couldn’t come up with anything smarter than applying brute force and he later mentioned in passing to not have seen anything smarter on forums he lightly perused, this year is the first time I go to bed each day in joyous anticipation of waking up, rushing to code some discrete solver.

Aoc/2024/1

Day one expectedly was but a warm-up; a kata in the classical sense. Solvable in a Haskell one-liner (the second part I didn’t elegantly get transformed into point-free notation):

{- aoc/2024/1/1 -}
main = sum . fmap abs . uncurry (zipWith (-)) . swap . fmap (snd <$>) . swap
  . fmap (snd <$>) . break fst . sort . zipWith ($) (cycle [(False,), (True,)])
  . fmap (read :: String -> Integer) . words <$> getContents >>= print

Aoc/2024/2

For the second day, I really wanted to use Ivy as Russ Cox had done so effortlessly in 2021 (though I unfortunately drive Ivy not with Acme but with Shell). Yet my APL understanding was too lacklustre to get it to work, making me give up and whip up a straight-forward Go solution (not shown herein). Already on day two, I had taken longer than a day to submit a solution. But I also wasn’t too interested in the early days.

# aoc/2024/2/1
{ cat <<EOI
op incordec rep = and/ ((up rep) == iota rho rep) | (down rep) == iota rho rep
op inrange rep =
  srt = rep[down rep]
  δ = 1 drop (-1 rot srt) - srt
  and/ (δ >= 1), (δ <= 3)
op safe rep = (incordec rep) & inrange rep
EOI
sed 's!^!safe !'
} | ivy | grep 1 | wc -l

Aoc/2024/3

On the third day, I realized everything in Shell. To sum everything up (Legacy sum computes a deprecated file checksum and does not sum up lists of decimal numbers!), I modified my nascent, unit-aware arbitrary-precision calculator dreisatz to read from stdin and not space-join its arguments (the ad-hoc, hacky solution chosen for any new command implementation).

# aoc/2024/3/2
grep -Po "(mul\((0|[1-9][0-9]{0,2}),(0|[1-9][0-9]{0,2})\)|do\(\)|don't\(\))" \
  | awk '/^do/{DISABLED=0}; /^don/{DISABLED=1}; /^m/{if(!DISABLED)print}' \
  | sed 's![mul()]!!g; s!,!*!g; a+' | xargs | sed 's! !!g; s!\+$!!' \
  | sed 's!$!=x!' | xargs dreisatz | grep -o '[0-9]*'

From day four onwards, I primarily wrote Go (aoc/2024/17/2 sees a little C).

Aoc/2024/4

Day four wasn’t too interesting⸺fiddling with two-dimensional char arrays.
Days three and four were coded in swift succession on the ICE from Hamburg to Tübingen. On-board WiFi worked flawlessly, if of a tad high latency.

Aoc/2024/5

Day five, on the other hand, lead me to pass a receiver-bound method to Go’s slices.SortFunc for an elegant core:

// aoc/2024/5/2

type PageOrdering struct { before, after map[int][]int }

func main() {
  var tot int

  po := NewPageOrdering()
  scanner := bufio.NewScanner(os.Stdin)
  for scanner.Scan() {
    // ...
    po.Leq(atoi(nm[:k]), atoi(nm[k+1:]))
  }

  for scanner.Scan() {
    ns := Fmap(strings.Split(scanner.Text(), ","), atoi)
    if slices.IsSortedFunc(ns, po.Cmp()) {
      continue
    }

    slices.SortFunc(ns, po.Cmp())
    tot += middle(ns)
  }
  must(scanner.Err())

  fmt.Println(tot)
}

Aoc/2024/6

Problems where you don’t need to optimize but only execute hide all of their complexity in parsing. Day six was nothing more. Yet me crudely implementing a (buggy!) representation of one infinite Cartesian plane quadrant *Quadrant[T] would cause confusion the coming days.

Aoc/2024/7

For day seven’s first part, I encoded all possible expressions inside an integer’s bits (since there were only ‘+’ and ‘*’ to choose from). When ‘||’ got added, I made good use of Go’s fresh-out-of-the-oven coroutines:

// aoc/2024/7/2

func Cartesian[S ~[]T, T interface{~int8 | ~int}](x T, n int) iter.Seq[S] {
  return func(yield func(S) bool) {
    if x <= 0 || n < 0 {
      return
    }

    xs := make(S, n)
    for {
      if !yield(xs) {
        return
      }

      j := len(xs)-1
      xs[j]++
      for xs[j] >= x {
        if j == 0 {
          return
        }
        xs[j] = 0
        j--
        xs[j]++
      }
    }
  }
}

Aoc/2024/8

Day eight was fun: type Pt = image.Point is a versatile two-dimensional vector representation and stepping to the end of the board to then step back in gcd-divided steps for aoc/2024/8/2 made for a neat little algorithm. I was, however, surprised to realize Go is missing integer-valued abs and gcd. Not that I had any reason to expect their existence after my many sleepless hours poring over Go’s stdlib.

// aoc/2024/8/1

func Choose2[T any](xs []T) iter.Seq[[2]T] {
  return func(yield func([2]T) bool) {
    for i := 0; i < len(xs); i++ {
      for j := i+1; j < len(xs); j++ {
        if !yield([2]T{xs[i], xs[j]}) {
          return
        }
      }
    }
  }
}

func abs(x int) int {
  return x * sgn(x)
}

func sgn(x int) int {
  switch {
  case x < 0:
    return -1
  default:
    return 0
  case x > 0:
    return +1
  }
}
// aoc/2024/8/2
// Cf. https://en.cppreference.com/w/cpp/numeric/gcd [2024-12-08]
func gcd(x, y int) int {
  switch {
  case x < 0 && y < 0:
    return gcd(-x, -y)
  case x < 0:
    return -gcd(-x, y)
  case y < 0:
    return -gcd(x, -y)

  case x == 0:
    return y
  case y == 0:
    return x
  case x < y:
    return gcd(y, x)
  default:
    return gcd(y, x % y)
  }
}

Aoc/2024/9

Brains off, code! was the theme for day nine. I missed a possible “slices.LastIndex” symbol.

// aoc/2024/9/2
func slicesLastIndex[S ~[]E, E comparable](s S, v E) int {
  for j := len(s)-1; j >= 0; j-- {
    if s[j] == v {
      return j
    }
  }
  return -1
}

Aoc/2024/10

Restricted graph hiking lead me to implement an iterator on day ten which proved versatile the coming days.

// aoc/2024/10/1
func CardinalSteps() iter.Seq[Pt] {
  return func(yield func(Pt) bool) {
    _ = yield(Pt{+1, 0}) && yield(Pt{0, -1}) &&
      yield(Pt{-1, 0}) && yield(Pt{0, 1})
  }
}

Aoc/2024/11

Day eleven had the affronting moment of implementing aoc/2024/11/1 as build in-memory, then count only to suffer a snub at aoc/2024/11/2 with me owning only non-exponentially-growing memory sticks.

// aoc/2024/11/2

type (
  Pebble int
  Pebbles map[Pebble]int
)

func blink(pebbles Pebbles) Pebbles {
  evolved := make(Pebbles)
  for pebble, count := range pebbles {
    if pebble == 0 {
      evolved[1] += count
    } else if s := strconv.Itoa(int(pebble)); len(s) % 2 == 0 {
      // strconv.Atoi assumes base 10,
      // so the possible leading zeroes don't trigger an octal sniff
      evolved[Pebble(atoi(s[:len(s)/2]))] += count
      evolved[Pebble(atoi(s[len(s)/2:]))] += count
    } else {
      evolved[pebble * 2024] += count
    }
  }
  return evolved
}

func main() {
  cast := func(x int) Pebble { return Pebble(x) }
  pebbles := Count(Fmap(cast, Fmap(atoi, stdinwords())))
  for range 75 {
    pebbles = blink(pebbles)
  }
  fmt.Println(Sum(maps.Values(pebbles)))
}

Aoc/2024/12

Finally, a tougher nut to crack: I fiddled with day twelve’s edge finding so long that I had to interrupt my coding to go to the doctor’s office. Fortunately, they offered an open WiFi and I could submit aoc/2024/12/2’s answer from inside the waiting room (the following is a refactored version a few hours after submission).

// aoc/2024/12/2
func main() {
  var price int
  garden := stdinbyteplane()
  step := func(Pt) iter.Seq[Pt] { return CardinalSteps() }
  for pt0 := range garden.Components(step) {
    area := iterLen(garden.FloodFill(step, pt0))
    perim := garden.CountEdges(step, pt0)
    price += area * perim
  }

  fmt.Println(price)
}

// Edge detection via four separate region expansions.
//
// pt0 is the representative of a component.
func (p *Plane[T]) CountEdges(step func(Pt) iter.Seq[Pt], pt0 Pt) int {
  var sides [4]Plane[bool]
  for pt := range p.FloodFill(step, pt0) {
    side := -1
    for enws := range CardinalSteps() {
      side++
      if p.Peek(pt.Add(enws)) != p.Peek(pt) {
        sides[side].Poke(pt.Add(enws), true)
      }
    }
  }

  var n int
  for _, side := range sides {
    n += iterLen(side.Components(step))
  }
  return n
}

Aoc/2024/13

That Friday was my birthday. I planned to wake up early at 5:50am to get going quickly but after falling back asleep for ten minutes, I was in such a daze that I couldn’t invert the 2x2 integer matrix this day’s problem ways about. It took me a 52:32 minutes to submit aoc/2024/13/1 and, as I didn’t brute-force it, 53:13 minutes to submit aoc/2024/13/2.
We suffered a power outageˣhich brought down my cellar-dwelling Raspberry Pi 2’s by-then-glorious uptime⸺and I felt too frail to attend a talk I badly wanted to witness.
Birthday dinner with my family later that day was a vile experience, too. Bad puzzle, bad day.

Aoc/2024/14

Aoc/2024/14/2 was utter garbage: Looking at white noise until one finds some picture isn’t solving puzzles. And the resulting christmas tree for day fourteen is framed and tucked arbitrarily somewhere on the bathroom floor. By far the worst Advent of Code question I have seen in my journey (which currently is 107 stars long).

Aoc/2024/15

I love Sokoban. Just not playing it (cf. 258). So on day fifteen I wrote a generic block-pushing-puzzle library for aoc/2024/15/1. When the boxes grew in aoc/2024/15/2, I wrote a companion library for arbitrarily-shaped boxes.

// aoc/2024/15/1
import "jfrech.com/goo/puzzle/boxpush"

func main() {
  warehouse := new(boxpush.World)
  var robot Pt
  var instrs []boxpush.Dir
  // parse ...

  for _, instr := range instrs {
    multipush := true
    warehouse.Push(robot, instr, multipush)
    if warehouse.Peek(robot.Add(instr.Vec())) == boxpush.Air {
      robot = robot.Add(instr.Vec())
    }
  }

  var tot int
  bounds := warehouse.Bounds()
  for pt, _ := range warehouse.All() {
    if warehouse.Peek(pt) == boxpush.Box {
      tot += 100 * (pt.Y - bounds.Min.Y) + (pt.X - bounds.Min.X)
    }
  }

  fmt.Println(tot)
}
// aoc/2024/15/2
import "jfrech.com/goo/puzzle/boxpush/glued"

func main() {
  warehouse := new(boxpush.World)
  // ...
  for {
    // ...
    trafo := func(pt Pt) Pt { return Pt{pt.X*2, pt.Y} }
    switch c {
    case '@':
      robot = trafo(pt)
      warehouse.PokeAir(trafo(pt))
      warehouse.PokeAir(trafo(pt).Add(Pt{1, 0}))
    case '.':
      warehouse.PokeAir(trafo(pt))
      warehouse.PokeAir(trafo(pt).Add(Pt{1, 0}))
    case 'O':
      warehouse.PokeAir(trafo(pt))
      warehouse.PokeAir(trafo(pt).Add(Pt{1, 0}))
      warehouse.PokeBox(boxpush.Box{trafo(pt), trafo(pt).Add(Pt{1, 0})})
    }
  }

  // ...
}

Aoc/2024/16

Day sixteen had be stumped for a bit. I had seen Russ Cox solve aoc/2021/23’s amphipod shuffling using a priority queue based on container/heap and parametric polymorphism. But when I had set up my priority queue, my solver choked on the combinatorial explosion which comes about due to the many equi-costing labyrinth cycle turn options. Figuring out in aoc/2024/16/1 to prune the cost-guided search using a global already-visited-map was insightful. Amending said global history with a record of alternate subsolutions to then reconstruct the union of all optimal paths in aoc/2024/16/2 was eye-opening.
The solver I had christened that day would later be modified to solve aoc/2024/18 and from there grow into a generic library.

Aoc/2024/17

Day seventeen. What a doozy! Aoc/2024/17/1 is as lame as unsalted broccoli. But aoc/2024/17/2, when read wrong, touches on undecidability. After all, defining some imperative DSL, writing a program in it and asking for the inverted program’s output can’t be solved in all generality.
So I tried brute-forcing in Go. That went nowhere, even after hastily parallelizing it to four cores.
I then bypassed my Go-written aoc/2024/17-DSL-interpreter by hand-transpiling the DSL-described program into C, but it never output anything:

/* aoc/2024/17/2 */
#include <stdbool.h>
#include <stdio.h>

bool prog(long long a) {
  int force[] = {2, 4, 1, 1, 7, 5, 4, 6, 0, 3, 1, 4, 5, 5, 3, 0, -1};

  a = a > 0 ? a : 1;
  long long b = 0, c = 0;
  int printed = 0;
  while (a) {
    b = a % 8;
    b = b ^ 1;
    c = a >> b;
    b = b ^ c;
    a >>= 3;
    b = b ^ 4;
    int out = b % 8;

    if (force[printed] != out)
      return false;
    printed++;
  }

  return printed == (sizeof force / sizeof (int) - 1);
}

int main() {
  for (long long a = 1;; a++)
    prog(a) && (printf("%lld\n", a), fflush(stdout));
}

I had no angle of approach. From looking at the DSL-written program in question, I knew the flow diagram was a single loop without prelude or epilogue:

; aoc/2024/17/2
2 4 ; bst: b <- a MOD 8
1 1 ; bxl: b <- b XOR 1
7 5 ; cdv: c <- a RSHIFT b
4 6 ; bxc: b <- b XOR c
0 3 ; adv: a <- a RSHIFT 3
1 4 ; bxl: b <- b XOR 4
5 5 ; out: PRINT (b MOD 8)
3 0 ; jzz: IF (a == 0) THEN HALT ELSE LOOP

I tried known compiler techniques: rewrite into SSA form (I knew I wanted to hit exactly 16 loops which I could then unroll) and force values backward:

; aoc/2024/17/2
a := UNKNOWN
b := 0
c := 0

a1_0 := a
b1_0 := b
c1_0 := c

b1_1 := a1_0 MOD 8
b1_2 := b1_1 XOR 1
c1_1 := a1_0 RSHIFT b1_2
b1_3 := b1_2 XOR c1_1
a1_1 := a1_0 RSHIFT 3
b1_4 := b1_3 XOR 4
d1 := b1_4 MOD 8
force d1 to 2
force a1_1 to positive

; fourteen more times

; ...
force d16 to 0
force a16_1 to 0

But how do you force the bitwise exlusive disjunction of two non-constants? How do you force a rightwards bit shift of two non-constants? Both would imply branching in the analysis which may then again accumulate enough search space that one would be better off brute-forcing.
Think of bit vectors! I thought and calculated an RSHIFT encoding on the level of individual bits:

    zabcd >> efg
=   zabcd >> e00
  | zabcd >> 0f0
  | zabcd >> 00g
=   0000z & 0000e
  | 00zab & 00fff
  | 0zabc & 0gggg

Thus I thought of representing each integer as 64 boolean variables, using the above SSA form to construct a non-linear boolean system of equations in thousands of variables, setting all of a’s bits to zero and, starting at the least-significant end, removing these equations until a solution was found (as I needed a solution which minimizes a’s numeric value). I hoped for the somewhat linear nature of SSA as a source to the system of equations to aid in solving it (as SAT, famously, is NP-complete and if I had a nondeterministic Turing machine, I wouldn’t be sitting in front of a forever-toiling C fragment).
By hand I had already proved a’s least significant bits couldn’t as a pack be 001.
But then again: a lot of bookkeeping effort with a high likelihood of producing a hard-to-solve non-linear system of boolean equations. I didn’t follow through on this approach.

What I did is stare at the program in question. I needed to find an a. What effect does changing it have on the program’s behaviour?
Asking the right question is oh so often in itself the answer!
Line three, c1_1 := a1_0 RSHFIT b1_2, is hard to reason about. But b1_1 := a1_0 MOD 8 is known. So the shift can be at most of size seven. The only other place where a is mentioned is in a1_1 := a1_0 RSHIFT 3. And the program only outputs d1 := b1_4 MOD 8. Thus, in each iteration, only seven consecutive bits of a contribute to the output and in each iteration, said contributing bit pack shifts by three leftwards.
Trying out 1024 values for a to produce the first wanted value, locking in all possibilities for the first pack of three bits and repeating fifteen times takes only a tenth of a second on my ThinkPad.

// aoc/2024/17/2
func main() {
  var prog *Prog
  // parse ...

  var force []int = prog.Text()
  b0, c0 := prog.B, prog.C

  run := func(a int) iter.Seq[int] {
    prog.A, prog.B, prog.C = a, b0, c0
    prog.Pc = 0
    return prog.Run()
  }

  as := make(map[int]struct{})
  for j := range (1 << 7) {
    as[j] = struct{}{}
  }

  for k := range len(force) {
    as2 := make(map[int]struct{})
    for left := range 8 {
      for right := range as {
        a := left << (7+3*k) | right
        if out, ok := Get(run(a), k); ok && out == prog[k] {
          as2[a] = struct{}{}
        }
      }
    }
    as = as2
  }

  a := slices.Min(slices.Collect(maps.Keys(as)))
  if !slices.Equal(slices.Collect(run(a)), force) {
    panic("unreachable")
  }
  fmt.Println(a)
}

After submission, I stopped my freshly then-yesterday unboxed ThinkPad T470s (boasting an i7!) whose tight C-written brute-forcing loop had toiled all day, only covering ~0.5% of the search space (assuming 1<<45 <= a < 1<<48 for which I had a slight hunch due to the a <- a RSHIFT 3 line).

Aoc/2024/18

Today, the eighteenth of December 2024, was strikingly similar to aoc/2024/16. And aoc/2024/18/2’s maze un-solving was brute-forceable, not even requiring a primitive optimization such as re-computing a solution only when the known has been blocked.
Watching optimality’s jittery quiddity is a treat each time around (cf. 230, 161).

aoc-2024-18-2.gif
Aoc/2024/18/2

I’m over it.

2024-11-02, post № 292

poetry, #elektronenhirnverdruss

For countless moons now have I withered,
told myself to fight a fight.
Possibly thought to be enlightened,
suppressed my self in fear of looming arrogance.
What for? An audience of at most one:
since all around me deafening set in
and I myself got bored of it.
Centuries ago, 𝗘𝗻𝗹𝗶𝗴𝗵𝘁𝗲𝗻𝗺𝗲𝗻𝘁 some tried to start.
And on their shoulders I now rest.
Yet thanking thanklessly toiling souls long gone
cannot fulfill one for too long.
Concentrated by imperialism,
industrialization, globalization, capitalism,
finance and neo-liberalism,
a might of such unfathomable extent has simmered,
has boiled⸺had overcooked and spewed,
engulfed; imposed on all of us: 𝗧𝗵𝗲 𝗕𝗶𝘁.
Oh, what box has lost its lid?
The foolishness knows no bound.
For that a myriad of other plagues
unleashed upon the cosmos
could have been healed,
escaped from on Kharon’s ride,
reckoned with.
No, no! It furthers our goals:
a beast, you call it, we did let loose.
Befriend it, fuse with it and we
will rise together in perpetuity.
No one is interested.
And all are blind!
A wretched goo of incompetence
seeps through the fabric of society,
devouring pride, compassion, togetherness.
All in a bid to please 𝗧𝗵𝗲 𝗕𝗶𝘁.
Not me no mores: I extricate,
I vindicate, commemorate
⸻yet reevaluate.
Life’s too short to keep up the taunt forever,
too vile and bitter is the fallout.
“Be free!” the peace dove exclamates,
soaring over cityscapes,
where of its kin the pigeons scurry,
held captive by their sorry ways
to peck in vain the concrete /pleɪn/.
A glass front breaks her neck.

Das ist kein Text. Das ist dumpf.

2024-10-27, post № 291

de, poetry, #leichte-sprache

Er sagt nichts.
Aus seinem Mund kommt kein Wort gekrochen.
Er steht bloß da.
Ich stehe auch da.
Dann verlasse ich ihn.
Das heißt: Ich stehe nicht mehr da.
⸻ Sicht·wechsel. ⸻
Es ist Freitag.
Es ist elf Uhr.
Freitags spielt Paula immer Skat.
Paula spielt Skat mit mir.
Skat kann man nicht alleine spielen.
Heute spielt Paula kein Skat.
Paula redet heute mit ihrem Freund.
Paula redet ab morgen nicht mehr mit ihrem Freund.
Dann spielt Paula wieder mit mir Skat.
⸻ Sicht·wechsel. ⸻
Ich setze mich in die Sonne.
Dort bestelle ich einen Birnen·saft.
Die Bedienung sagt: ›Kommt sofort!‹
Aber mein Birnen·saft kommt nicht sofort.
Das dauert eine Weile.
Ein Mann steht auf der Straße.
Die Straße ist vor dem Café.
Er ist einsam.
Er steht alleine.
Er starrt auf den Boden.
Eine Frau kommt dazu.
Dann geht die Frau.
Der Mann steht auf der Straße.
Er ist einsam und er ist alleine.
Ich habe meinen Birnen·saft.
Ich trinke meinen Birnen·saft.
⸻ Sicht·wechsel. ⸻
Ich habe frei.
Das ist selten.
Ich spaziere durch meine Stadt.
Die Sonne scheint.
Ich will einen Tee trinken.
Zu meiner Linken ist ein Café.
Das Café ist dreckig.
Im Garten sitzt ein Mann.
Er genießt die Sonne.
Er redet mit der Kellnerin.
Die Kellnerin ist enttäuscht.
Zu meiner Rechten steht ein Mann.
Er ist alleine.
Hier trinke ich keinen Tee.
⸻ Sicht·wechsel. ⸻
›Ich hasse dich!‹
Das sagt sie.
Danach spuckt sie auf den Boden.
Dann geht sie.
⸻ Sicht·wechsel. ⸻
Ich arbeite im Café.
Die Arbeit macht mir keinen Spaß.
Ich will Texte schreiben.
Das darf ich nicht.
Ich muss essen.
Das hat man mir gesagt.
Deshalb darf ich nicht schreiben.
Deshalb muss ich kellnern.
Heute scheint die Sonne.
Deshalb kommen viele Leute in den Garten.
Das sagt meine Chefin.
Aber in dem Garten sitzt nur ein Mann.
Der Mann bestellt.
Ich finde die Flasche nicht.

Entstanden während erster Beschäftigungen mit Leichter Sprache im Rahmen der Themenwoche Literatur für Alle!. Tübingen, 2024‐10‐27.

Movie review: The Beekeeper

2024-08-31, post № 290

movie-review, #blockbuster, #technologieverdruss, #hakr

The Beekeeper [1] positions itself at the non-personal end of an emerging niche in blockbuster media tackling society’s struggles with the poorly understood repercussions mass-adopted digital technology without gatekeepers brings about.

Whereas over a quarter century ago, Hackers [2] celebrated a subculture in pursuit of freedom fighting against a rigid system of rules, without a doubt founded on the emergence of the Web and affordable Internet access evoking liberating visions of a digitally empowered society allowing the individual to flourish in its idiosyncrasy, twenty years later, when all shine of such musings seems to have been ground off, Hacked [3] depicts a deeply personal side of technology misuse and the perils bound up in its unquestioned glorification. Also personal, Inside [4] traps Nemo (played by Willem Dafoe) in an apathetic fight for relief in form of the sky whose ending leaves open if man has bested digital prison or vice versa.
The Beekeeper is insofar a novelty in popular media as it combines the non-glorifying, non-cliché omnium-gatherum of topics exemplified by the term hakr with the Free West’s struggle to uphold its rule of law faced with competent, multi-national adversaries empowered by p2p chatrooms.

Whilst a purist may turn up their nose at the visual and dramaturgical fluff which inseparably comes with a blockbuster, when keeping an open mind and seeing the story within a movie playing by the rules for being played to a non-vanishing audience, a polytheistic fable can be reclaimed in which an angered god descends onto a failing people which has lost their sense of righteousness, surgically removing the demon haunting it and disappearing. Seen from this angle, one isn’t confused by Adam Clay’s (played by Jason Statham) executive prowess nor his misaligned morals. As a non-human entity, the interpretation herein proclaims, unbound by classically freedom-preserving rule sets which appear to crumble in the globalized, digitalized world, Clay’s crassness can be viewed as a window to the horrors which await when the non-state organizations overpower.

Doomish as Civil War [5], but keeping itself to the more narrow topic of digital misuse aided through societal-wide ignorance, The Beekeeper does two things seldom seen together in popular cinema: a) questioning the efficacy of and ignoring the rule of law and b) tackling digital technology misuse without glorifying its technical side, focusing on the human misery.

REFERENCES.
  [1] "The Beekeeper" (German version). 2024.
  [2] "Hackers – Im Netz des FBI" (German version; English title: "Hackers"). 1995.
  [3] "Hacked – Kein Leben ist sicher" (German version; English title: "I.T."). 2016.
  [4] "Inside" (English version). 2023.
  [5] "Civil War" (German version). 2024.

Lower semicontinuity’s misremembrance

2024-08-03, post № 289

mathematics, #analysis, #alternate-definition, #gastropod, #symmetry

Snails are surprisingly fast: you look at them and they creep so slowly as to strain your attention. Yet you look away for an undefined moment and their progress in distance appears wholly bewildering. Then again, I would wager to outrun most snails in a 200-meter dash.

I think symmetry’s ubiquity is an equally fickle observation; you may only be able to bear whitness to it once you have already manifested it for yourself. Notably notationally; among the following lines

\liminf_{y\to x\neq y}f(y)\leq f(x) \quad\textbf{(Q)}
f(x)\leq\liminf_{y\to x\neq y}f(y) \quad\textbf{(C)}

for a map f:X\to\mathbb{R} from a topological space X to the real line and a fixed point x\in X, precisely one is the definition of lower semicontinuity, the other but a figment of a symmetry-ravenous mind.

I knew for a long time about \textbf{(Q)}’s questionability, but only two days ago I realized how separate a statement it is. Only the obvious implication \lnot\textbf{(C)}\implies\textbf{(Q)} holds with all three other conjunctions being possible: \textbf{(C)}\land\lnot\textbf{(Q)} satisfied by 1-\chi_{\{0\}} on X=\mathbb{R} at x=0, \textbf{(C)}\land\textbf{(Q)} satisfied by \chi_{]{}0,\infty{}[} on X=\mathbb{R} at x=0 and \lnot\textbf{(C)}\land\textbf{(Q)} satisfied by \chi_{[0,\infty{}[} on X=\mathbb{R} at x=0.

Curiously, the infamous \chi_{\mathbb{Q}} satisifies \textbf{(Q)} at every point, intuitively showing \textbf{(Q)}’s inaptitude of representing an (even weakened) interpretation of continuity.

Book review: How to Do Nothing

2024-07-06, post № 288

book-review, #technologieverdruss

Cold War’s over, semiconductors have permeated the fabric of society, forests are afire. At times one may feel hard-pressed not to jettison it all in light of our impending doom.
Grasping for meaning in this maelstrom of angst, Jenny Odell documented her way out of the sharp-frozen state of mind 2016’s potus crowning entailed. Of undoubtable value as a contemporary anthropological artifact, its philosophical value or its idea’s practical viability is disenthraling.

-=-

How to Do Nothing [O19 [1]] is strongest in its first two-and-a-half chapters, their content comprising Jenny Odell’s talk of the same title which she herself regards as the true form [O24 [2]] of her expression what it means to do nothing.
Yet the very, “nothing”, isn’t to be understood as extremely as one may be lead to believe initially: layed out in many pages, it boils down to not accumulating evermore novel media-powered dependences. At face value an innocuous-seeming objective, Odell makes abundantly clear the myriad of obstacles she, and by extension the common man, faces in our media-saturated world. Never able to poke through the haze and attain true separation from a vague unease pronounced “media”, over two thousand years of human philosophy and art are essayed to discuss, with a prominent focus on nature and non-artifact art.

Where How to Do Nothing truly shines is in its quality as a diary, one human’s personal story: wittily written, it names art pieces Odell has created, witnessed or espied, it lets one cursorily plunge into growing up in the technologized Bay area and depicts how a love for nature and hiking blossoms through bird watching.

Yearning without attaining freedom, the tribulations of past human attempts at removing oneself from the larger society are of particular interest. Odell does well not to romanticize the communes of last century’s second half, recognizing the possibility of an innate self-destruction caused by an impossibility of stable small-scale societies, yet cannot hold that thought for long or gain any insight from it beyond how historically, few if any actively sabotaged a commune. In the same breath, however, she blindly regurgitates the all-too-commonplace stance that social media moguls are to be the villains of our time.
A similar observation has to be made with the way in which she treats her quotations: after a succint paragraph from an influential writer has introduced its often powerful impetus, only her recounting of their thoughts seems able to show depth and merit. Before too long, she wanders off in a shallow mindscape of hopes and sorrows before repeating the procedure once more.

Crashing GC in 57 bytes

2024-05-27, post № 287

programming, #lang:go, #internal-compiler-error

Terser than GCC’s C++ (cf. 235), Go’s standard implementation can be forced to doubt itself in a mere 57 bytes:

$ go version
go version go1.22.1 linux/amd64
$ printf 'package main;func main(){panic(0);x:=0;l:for{goto l};_=x}' >/tmp/ice.go
$ wc -c /tmp/ice.go
57 /tmp/ice.go
$ go run /tmp/ice.go
# command-line-arguments
CLOSURE [/tmp/ice.go:1:56:var x int]
<unknown line number>: internal compiler error: assertion failed

Please file a bug report including a short program that triggers the error.
https://go.dev/issue/new

Without having analyzed the compiler, black-box behavioural poking revealed that truly fickly a panic has to be followed with a variable declaration whose use entwines a label; else all one gets is an immediately-panicking or non-terminating executable:

package main

func main() {
	panic(0)

	x := 0

l:
	for {
		goto l
	}

	_ = x
}

At first, it irritates you, since⸺although you expect a plethora of compilation and test failures whilst developing⸺the error looks off. At closer inspection, a joyful rush grips you as you might be the first human being engaging in this specific dialogue with your compiler. So you stop everything else and golf away to extract an erroring nub. Whole swaths of code you rip out without a care for your program you once developed. The tiniest of changes⸺even ones which go in between equivalent source formulations⸺make the compiler snap out of its delusions, rendering it able to produce an executable. But you persevere, wanting the compiler to fail again and again at compiling a program without any use.

Cf. Go issue #67661

Schwund

2024-05-11, post № 286

politics, #diary, #elektronenhirnkritik

“Mir gelingen keine Lieder mehr, die ich mit wohl­ge­stimm­tem Saiten­klang begleite. Denn Lieder sind das Werk sorg­loser Phanta­sie. (...) Ich schreibe, und meine Au­gen werden be­taut von quel­len­den Tränen.” [N [1], S. 158—171: XV: Sappho Phaoni]

Es fällt mir zunehmed schwer, einen frohen Gedanken zu fassen, wenn ich die Haustür verlasse: ein erschreckender Teil meiner gemeinhin als Mitmenschen Bezeichneten ist dahin über­ge­gangen, Spion in Auge und Ohr für Unbekanntes zu spielen: in Videochats zwingen sie, ohne meine Person zu beachten, mein Abbild in die diffusen Zwänge der Cloud, in ihren Spionage-getunten Auto­mobilen überfahren sie überlegen grinsend meine Persönlich­keits­rechte, Überwachungs­kameras werden weit auf den Bürger­steig geneigt und Tür­klingeln filmen auf die Straße, wo sie meine Privat­sphären­ansprüche als EU-Bürger im öffentlichen Raum zertreten.

Ich halte für eine besonders in den letzten Jahren grundlegend verschlafene Komponente die durch unsere Gesellschaft triefende Inkompetenz, aus der sich im Lichte der komplexen Folgen von Digital­technologie­nutzung schnell gefühlte Boshaftigkeit entwickelt: Anscheinend werden rechtlich oder moralisch vertretbare Winkel für Festmonturkameras nicht beachtet, Systeme wer­den in mangel­haft bis ungenügendem Zustand — erstellt von Individualvorteil-fröhnenden Ig­noranten ohne Gespür für Gesamtgesellschaftliches — ausgeliefert und in Betrieb genommen.
Cyber­security hat sich von einer geistig lohnenden Spiel­wiese diskreter Strukturen im Schnitt­gebiet zur Wirklich­keit zu einem eintönigen Er­nüchterungs­fest mensch­licher Ab­stumpfung ge­wandelt.

In diesem Sinne steht der Hoffnugsvollerer erdachten “friedlichen Koexistenz” [B24 [2]] gegenwärtig nicht bloß ein erschütternder Identitätsverlust entgegen sondern mithin eine kindliche Blindheit ihrer Unmöglichkeit [H80 [3]] der Implementation gegenüber.

Der dadurch resultierende, weitreichende Vertrauensverlust sollte auch nicht vernach­lässigt wer­den: falls sich nicht in vielen Köpfen eine Entprüdung bezüglich Datenverfügbarkeit breit macht — eine Gesellschaft ohne Geheimnisse der einzelnen Teilnehmenden ist zumindest im Grauen durch­aus denkbar — halte ich einen abrupten Kipppunkt, ab dem die kontinuierlich auftretenden, jedes Mal un­ver­zeih­lichen Sicherheits­patzer schlicht zu viel und un­trag­bar werden, für un­ab­wend­bar.

Ich gucke tatenlos zu, wie eine Welt, derer ich kein Bürger sein konnte und deren Schönheit mir bloß in aufgebauschten Erzählungen und brüchigen Artifakten vorliegt, unwiederbringbar in Trüm­mern versinkt.
Sollte es tatsächlich so sein, dass mir diese Gesellschaft einen Platz in ihr nicht verwehrt, so zeich­net sich fortschreitend klarer ab, dass ich das, was sie mir vorlegt, aus tiefem Ekel ablehne.

Jonathan Frech's blog; built 2024/12/19 23:13:08 CET