Uiua: Weekly challenge 242
Tags: uiua, programming, esoteric, learning
Published: 2023-11-11 13:56:20

## Table of contents

1. [Introduction](#introduction)
1. [Task 2](#task-2)
1. [Task 1](#task-1)

## Introduction <a name="introduction"></a>

[Uiua](http://uiua.org) is an interesting new language. Strongly influenced by [APL](https://tryapl.org) and [BQN](https://mlochbaum.github.io/BQN/), it's array-oriented and stack-based. To explore it briefly, I will walk through my solutions to this week's *[Perl weekly challenge (242)](https://theweeklychallenge.org/blog/perl-weekly-challenge-242/)*.

Uiua has an excellent [language tour](https://www.uiua.org/docs/tour) as well as a [tutorial](https://www.uiua.org/docs#tutorial) on its own site, which I'd recommend you go through if you're just starting out. I'm going to assume you have at least some syntactic familiarity with the language already.

### [Task 2](https://theweeklychallenge.org/blog/perl-weekly-challenge-242/#TASK2)

We'll actually start with Task 2 this week, since it's way easier.

Here is the problem description:
```
You are given `n x n` binary matrix.

Write a script to flip the given matrix as below.

1 1 0
0 1 1
0 0 1

a) Reverse each row

0 1 1
1 1 0
1 0 0

b) Invert each member

1 0 0
0 0 1
0 1 1
```

We'll start by putting the example matrix on the stack, in Uiua notation
```uiua
[[1 1 0] [0 1 1] [0 0 1]]
```

giving
```uiua
╭─
╷ 1 1 0
  0 1 1
  0 0 1
        ╯
```

Reversing each row can by done by a combination of the [`≡ rows`](https://www.uiua.org/docs/rows) and [`⇌ reverse`](https://www.uiua.org/docs/reverse) functions. Like this:
```uiua
[[1 1 0] [0 1 1] [0 0 1]]
≡⇌
```

giving
```uiua
╭─
╷ 0 1 1
  1 1 0
  1 0 0
       ╯
```

That takes care of part a). What we need to do now is just reverse each element. Since most simple functions in Uiua are *pervasive*, this is as simple as calling the [`¬ not`](https://www.uiua.org/docs/not) function on our previous result. Like this:

```uiua
[[1 1 0] [0 1 1] [0 0 1]]
¬ ≡⇌
```

giving
```uiua
╭─
╷ 1 0 0
  0 0 1
  0 1 1
        ╯
```

which is the expected answer. In the task there were two additional examples:
#### Example 1

```
Input: @matrix = ([1, 1, 0], [1, 0, 1], [0, 0, 0])
Output: ([1, 0, 0], [0, 1, 0], [1, 1, 1])
```
#### Example 2

```
Input: @matrix = ([1, 1, 0, 0], [1, 0, 0, 1], [0, 1, 1, 1], [1, 0, 1, 0])
Output: ([1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 1], [1, 0, 1, 0])
```

Let's put our logic in a function:
```uiua
FlipMatrix ← ¬≡⇌
```

and add these examples as unit tests by combining [`⍤ assert`](https://www.uiua.org/docs/assert) and [`≍ match`](https://www.uiua.org/docs/match) in a [`--- test scope`](https://www.uiua.org/docs/testing):

```uiua
---
FlipMatrix [[1 1 0] [1 0 1] [0 0 0]]
⍤.        ≍[[1 0 0] [0 1 0] [1 1 1]]

FlipMatrix [[1 1 0 0] [1 0 0 1] [0 1 1 1] [1 0 1 0]]
⍤.        ≍[[1 1 0 0] [0 1 1 0] [0 0 0 1] [1 0 1 0]]
---
```

Both unit tests pass, so we are done with Task 2.

### [Task 1](https://theweeklychallenge.org/blog/perl-weekly-challenge-242/#TASK1)

Let's move on to the more challenging task of the two. Here is the problem description:

```
You are given two arrays of integers.

Write a script to find out the missing members in each other arrays.
```

Let's start with the first example.
#### Example 1

```
Input: @arr1 = (1, 2, 3)
       @arr2 = (2, 4, 6)
Output: ([1, 3], [4, 6])

(1, 2, 3) has 2 members (1, 3) missing in the array (2, 4, 6).
(2, 4, 6) has 2 members (4, 6) missing in the array (1, 2, 3).
```

Since we'll be working with these example arrays a lot, let's start by putting them into variables `a` and `b`:
```uiua
a ← [1 2 3]
b ← [2 4 6]
```

To get what members are common between the two arrays we can use [`∊ member`](https://www.uiua.org/docs/member) like this:
```uiua
∊ a b
```

which gives us a filter mask with 1s corresponding to the common elements:
```
[0 1 0]
```

We want the missing ones (i.e. the *not* common elements), so we invert this array with [`¬ not`](https://www.uiua.org/docs/not):
```uiua
¬∊ a b
```

giving
```
[1 0 1]
```

We can now apply this inverted mask to our original array using [`▽ keep`](https://www.uiua.org/docs/keep) to get the missing members
```uiua
¬∊ a b
▽: a
```

giving
```
[1 3]
```

which is correct. Note that this could also be put on a single line like this:
```uiua
▽: a ¬∊ a b
```

We also need to do the opposite by reversing the arrays in our input
```uiua
▽: b ¬∊ b a
```

giving
```
[4 6]
```

which is also correct. Since the output should be in the form of a single 2d array
```
Output: ([1, 3], [4, 6])
```

we *could* do it like this (variable names are case sensitive)
```uiua
A = ▽: a ¬∊ a b
B = ▽: b ¬∊ b a
[A B]
```

or by using [`⊟ couple`](https://www.uiua.org/docs/couple) like this
```uiua
A = ▽: a ¬∊ a b
B = ▽: b ¬∊ b a
⊟ A B
```

both giving the expected 2d array
```
╭─
╷ 1 3
  4 6
      ╯
```

Let's try to do away with some repetition. We'll start by creating a single function that gets us the missing members in one direction between two arrays:

```uiua
F ← ▽¬∊,
```

And combining them with [`⊟ couple`](https://www.uiua.org/docs/couple)
```uiua
⊟  F b a  F a b
```

Note that this is equal to
```uiua
⊟  F : a b  F a b
```

Now things start to get interesting. Notice the symmetry, where we do two different operations to the same set of values. Uiua has a couple interesting functions for doing that, in this case we'll use [`⊃ fork`](https://www.uiua.org/docs/fork):
```uiua
⊟ ⊃(F∶)(F) a b
```

still giving us what we want
```
╭─
╷ 1 3
  4 6
      ╯
```

So far so good.
#### Example 2

```
Input: @arr1 = (1, 2, 3, 3)
       @arr2 = (1, 1, 2, 2)
Output: ([3])

(1, 2, 3, 3) has 2 members (3, 3) missing in the array (1, 1, 2, 2). Since they are same, keep just one.
(1, 1, 2, 2) has 0 member missing in the array (1, 2, 3, 3).
```

If we try our last function on this new data
```uiua
a ← [1 2 3 3]
b ← [1 1 2 2]
F ← ▽¬∊,
⊟⊃(F∶)(F) a b
```

we get an error
```
Error: Cannot couple arrays with shapes [2] and [0]  
at 4:1  
4 | ⊟ ⊃(F∶)(F) a b  
    ─
```

This is because arrays in Uiua must have a uniform shape, i.e. the same number of elements/rows/subarrays at each level. The solution is to [`□ box`](https://www.uiua.org/docs/box) the result of `F`:
```uiua
⊟⊃(□F∶)(□F) a b
```

giving
```
[⟦3 3⟧ ⟦⟧]
```

Notice the `⟦⟧` meaning it's a boxed array. There are two problems left to solve here though. First we want to get rid of the duplicate 3 in the first box. We'll use [`⊝ deduplicate`](https://www.uiua.org/docs/deduplicate) for that:
```uiua
⊟⊃(□⊝F∶)(□⊝F) a b
```

which works as expected
```uiua
[⟦3⟧ ⟦⟧]
```

We also want to get rid of the empty second box altogether. We can do that by taking the [`⧻ length`](https://www.uiua.org/docs/length) of each row and then [`▽ keep`](https://www.uiua.org/docs/keep) the ones `>0`:

```uiua
▽>0≡⧻. ⊟ ⊃(□⊝F∶)(□⊝F) a b
```

giving us
```uiua
[⟦3⟧]
```

which is correct! Putting it altogether, we can inline `F` for brevity and add our two examples as unit tests:

```uiua
MissingMembers ← ▽>0≡⧻. ⊟⊃(□⊝▽¬∊,∶)(□⊝▽¬∊,)

---
⍤. ≍{[1 3][4 6]} MissingMembers [1 2 3]   [2 4 6]
⍤. ≍{[3]}        MissingMembers [1 2 3 3] [1 1 2 2]
---
```

The unit tests pass and we're happy once again!

Was it hard or easy to follow along? Do you want more content like this? Leave a comment!