## Thursday, 29 January 2015

### new function: pretty print a table

Just as promised recently, we can add more functions when we think of a new need. Today, it took a while, but I wrote a pretty print table function. Feed it a superposition, apply a bunch of operators to it, then spit out a pretty table.

General usage:

So, here are some examples. First up temperature:
```-- NB: that due to quirks of the parser we need to do these two first:
-- (essentially casting function operators {F,K} to literal operators)
sa: F |*> #=> F |_self>
sa: K |*> #=> K |_self>

-- now, spit out a temperature table:
sa: table[C,F,K] range(|C: 0>,|C: 100>,|10>)
+--------+-----------+-----------+
| C      | F         | K         |
+--------+-----------+-----------+
| C: 0   | F: 32.00  | K: 273.15 |
| C: 10  | F: 50.00  | K: 283.15 |
| C: 20  | F: 68.00  | K: 293.15 |
| C: 30  | F: 86.00  | K: 303.15 |
| C: 40  | F: 104.00 | K: 313.15 |
| C: 50  | F: 122.00 | K: 323.15 |
| C: 60  | F: 140.00 | K: 333.15 |
| C: 70  | F: 158.00 | K: 343.15 |
| C: 80  | F: 176.00 | K: 353.15 |
| C: 90  | F: 194.00 | K: 363.15 |
| C: 100 | F: 212.00 | K: 373.15 |
+--------+-----------+-----------+
```
Now, what is going on underneath? Well the first column is just the superposition we have fed in (and uses the first operator "C" as its column heading), then the next two columns are generated by applying the F and K literal operators to the incoming superposition.

Next, some general info about a couple of people. First load up in sw format:
mother |Fred> => |Jane>
father |Fred> => |Robert>
age |Fred> => |age: 21>
height |Fred> => |cm: 179>

mother |Sam> => |Betty>
father |Sam> => |Tom>
age |Sam> => |age: 27>
height |Sam> => |cm: 183>

mother |Nicole> => |Bev>
height |Nicole> => |cm: 168>
```-- Now pretty print as a table:
sa: table[name,mother,father,age,height] (|Fred> + |Nicole> + |Sam>)
+--------+--------+--------+---------+---------+
| name   | mother | father | age     | height  |
+--------+--------+--------+---------+---------+
| Fred   | Jane   | Robert | age: 21 | cm: 179 |
| Nicole | Bev    |        |         | cm: 168 |
| Sam    | Betty  | Tom    | age: 27 | cm: 183 |
+--------+--------+--------+---------+---------+
```
Noting that it gracefully handles not knowing something, in this table, Nicole's father and age.

Next example, pretty printing some of what we know about early US presidents:
```sa: load early-us-presidents.sw
sa: table[name,full-name,president-number,party] "" |early US Presidents: _list>
+------------+---------------------------+------------------+------------------------------+
| name       | full-name                 | president-number | party                        |
+------------+---------------------------+------------------+------------------------------+
| Washington | person: George Washington | number: 1        | party: Independent           |
| Adams      | person: John Adams        | number: 2        | party: Federalist            |
| Jefferson  | person: Thomas Jefferson  | number: 3        | party: Democratic-Republican |
| Madison    | person: James Madison     | number: 4        | party: Democratic-Republican |
| Monroe     | person: James Monroe      | number: 5        | party: Democratic-Republican |
| Q Adams    | person: John Quincy Adams | number: 6        | party: Democratic-Republican |
+------------+---------------------------+------------------+------------------------------+

sa: years-in-office |*> #=> extract-value president-era |_self>
sa: table[name,years-in-office] "" |early US Presidents: _list>
+------------+------------------------------------------------------+
| name       | years-in-office                                      |
+------------+------------------------------------------------------+
| Washington | 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797 |
| Adams      | 1797, 1798, 1799, 1800, 1801                         |
| Jefferson  | 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809 |
| Madison    | 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817 |
| Monroe     | 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825 |
| Q Adams    | 1825, 1826, 1827, 1828, 1829                         |
+------------+------------------------------------------------------+
```
Now, another example that ties in with my recent post:
```-- load up some knowledge:
age |person: Emma> => |age: 12>
age |person: Fred> => |age: 17>
age |person: Sam> => |age: 18>
age |person: Liz> => |age: 19>
age |person: Jack> => |age: 20>
is-teenager |person: *> #=> do-you-know drop-below[13] drop-above[19] pop-float age |_self>
is-adult |person: *> #=> do-you-know drop-below[18] pop-float age|_self>
|list> => |person: Emma> + |person: Fred> + |person: Sam> + |person: Liz> + |person: Jack>

-- take a look in table format:
+--------------+---------+-------------+----------+
| name         | age     | is-teenager | is-adult |
+--------------+---------+-------------+----------+
| person: Emma | age: 12 | no          | no       |
| person: Fred | age: 17 | yes         | no       |
| person: Sam  | age: 18 | yes         | yes      |
| person: Liz  | age: 19 | yes         | yes      |
| person: Jack | age: 20 | no          | yes      |
+--------------+---------+-------------+----------+
```
Now, an example that ties in with my example of a simple network:
```-- load up the data:

-- define some operators:
-- (and again, due to the parser, we have to do it indirectly)
sa: O2 |*> #=> O^2 |_self>
sa: O3 |*> #=> O^3 |_self>
sa: O4 |*> #=> O^4 |_self>
sa: O5 |*> #=> O^5 |_self>

-- take a look:
sa: table[position,O,O2,O3,O4,O5] relevant-kets[O]
+----------+--------+--------+--------+--------+--------+
| position | O      | O2     | O3     | O4     | O5     |
+----------+--------+--------+--------+--------+--------+
| a1       | a2     | a3     | a4     | a5     | a6     |
| a2       | a3     | a4     | a5     | a6     | a7     |
| a3       | a4     | a5     | a6     | a7     | a8     |
| a4       | a5     | a6     | a7     | a8     | a9     |
| a5       | a6     | a7     | a8     | a9     | a10    |
| a6       | a7     | a8     | a9     | a10    | a1, b1 |
| a7       | a8     | a9     | a10    | a1, b1 | a2, b2 |
| a8       | a9     | a10    | a1, b1 | a2, b2 | a3, b3 |
| a9       | a10    | a1, b1 | a2, b2 | a3, b3 | a4, b4 |
| a10      | a1, b1 | a2, b2 | a3, b3 | a4, b4 | a5, b5 |
| b1       | b2     | b3     | b4     | b5     | b6     |
| b2       | b3     | b4     | b5     | b6     | b7     |
| b3       | b4     | b5     | b6     | b7     | b1     |
| b4       | b5     | b6     | b7     | b1     | b2     |
| b5       | b6     | b7     | b1     | b2     | b3     |
| b6       | b7     | b1     | b2     | b3     | b4     |
| b7       | b1     | b2     | b3     | b4     | b5     |
+----------+--------+--------+--------+--------+--------+
```
And I guess that is about it. This thing is going to be useful all over the place.

Update: an important thing to note is that these tables are not just of stored values. Some of the entries (eg, is-teenager, is-adult, years-in-office) are calculated at the time we generate the table. And they are again generated next time we ask the code to spit out a table. Remember, to generate our tables we are applying operators to the incoming superposition, not just looking up values. One consequence is that if in the background we update Emma's age (she had a birthday, perhaps, or we discovered we had made a mistake) the is-teenager and is-adult operators will do the right thing. No need to update those elements manually, as we would have to do if we were working with just stored values. Besides, if you do want to store values, instead of calculating over and over with each table, just use the map function. Perhaps I will explain later! Of course, if you do this, and then you change the definition of your operator, then the stored values will not be updated.

Another thing to note is that if you want a different name for your column heading than the operator name, just use the standard method for defining an alias. eg:
better-column-name |*> #=> unwanted-operator-name |_self>