Fifty Shades of J/Chapter 12
Table of Contents ... Glossary ... Previous Chapter ... Next Chapter
Principal Topics
- :. (obverse) :: (adverse) /. (key) ^: (power conjunction) b. (basic characteristics), inverse, compound interest, frequency tables, currying, scans, alternative verbs, error control
Obverse to Adverse
Welcome to the Vector Value excursion from Obverse Central to Adverse! Don’t forget you need an inverse for the return journey – personalised if you like – and note that the inverse is also mandatory (a) when the train gets under (&.) -way and (b) when it powers (^:) up with a negative argument. For many primitive monadic verbs and a few dyadic ones an inverse function is well defined, and there’s a list of these on a billboard further down the line. For example logarithm (^.) and power (^) are inverse operations, and this underlies the use of &. and ^: in the following examples
log=:^. 2+&.log 3 NB. e to the power ln2 + ln 3 6 2 ^.^:(_1)3 NB. 2 inverse-log (that is, to the power) 3 8 2 ^.^:(_2)3 NB. 2 inv-log inv-log 3 256
The first of these examples performs a transformation, ‘log to base e’, on both arguments prior to the primary operation plus, then performs the ‘inverse log’ transformation on the result. In the second and third examples parentheses are necessary to separate the arguments of the adverb (^:) and the adverbially modified verb (^.).
Suppose that through some perversity you decided to conclude the log operation by squaring rather than taking anti-logs
log=:^. :. *: NB. log with "square" as obverse 2 +&.log 3 NB. square of (ln 2 + ln 3) 3.2104
It is hard to see the circumstances in which this would be a sensible thing to do. However when you define your own verbs, J may not be able to define an inverse, and so you are given the opportunity to define your own through obverse. The obverse does not need to have a direct connection with the primary verb, nor does it affect its operation, other than in the contexts of under and negative power.
Here is another example with an obverse in which a primary operation joins names which are to have trailing blanks deleted prior to the join, with a final comma to be added after the append
dtb=:({.~i.&' ') :. (,&',') NB. delete trailing blanks (dtb 'mickey '),'*' NB. obverse does not affect mickey* NB. normal operation 'mickey ' ,&.dtb 'rooney ' mickeyrooney,
In ordinary usage the obverse side of a coin means the side commonly turned towards you, which in turn usually means ‘heads’ as opposed to ‘tails’. This reflects quite well the idea of obverse in J, because it emphasises (a) that when you use it you are thinking of a verb as a two-sided object, and (b) as with a coin there is no reason why the designs on the two sides should be directly related, although often the relationship is inverse in nature. Another example involves a frequency table verb frtab
x=:0 0 1 1 2 2 3 frtab=:+/"1@= frtab x 2 2 2 1
A natural inverse operation would be to ‘unwrap’ the frequencies back to the original data which is what the verb convert=:# i.@# does. So redefine
frtab=:+/"1@= :.convert frtab ^:_1 frtab x 0 0 1 1 2 2 3
The conductor will now give a further demonstration of obverse by converting between percentages and multiples as in, e.g. handling compound interest calculations. Suppose the percentage growth rates of an investment are known for a number of years, and it is desired to compute the average overall growth rate throughout the entire period. The following two verbs convert percentages to and from multiples
ptok=:>:@(*&0.01) NB. %age to multiple, 5 -> 1.05 ktop=:%&0.01@<: NB. multiple to %age, 1.05 -> 5 */ptok 5 6 13 _12 0 1.10677
Now suppose that this result should be given as percentage
ptok=:>:@(*&0.01) :. ktop NB. ptok with obverse */&.ptok 5 6 13 _12 0 10.6767
To compute the average, as opposed to total, growth over the period introduce under
gm=:(+/%#)&.(^."_) NB. geom mean(=arith mean under log) gm&.ptok 5 6 13 _12 0 2.04959
(The rightmost characters of gm -- enclosed necessarily by parentheses -- are necessary to make it into a scalar verb.)
It is reasonable to retain the name ptok for the obverse-enriched verb since adding the ‘flip side’ verb ktop does not affect its previous function; it is only in the presence of under and negative power that the enrichment occurs. In this case the obverse is just the inverse, which J is smart enough to figure out for itself, since it has a rule that the inverse of a verb u@v is (v^:_1)@(u^:_1), assuming of course that u and v are among the list of primitive verbs for which inverses can reasonably be computed, as is the case with ptok. So why bother to write an obverse when all those bright J folks have already given you what you probably wanted anyway, and moreover have provided a conjunction b. which by joining a verb to _1 returns its obverse
ptok=:>:@(*&0.01) NB. back to the original ptok ptok b. _1 NB. compute the obverse… 100&*@<: NB. …which is identical to ktop.
Well, let’s suppose that on the flip side (converting multiples back to percentages) you decide to display an explicit percent sign. Easy, just do
mut=:,&'%'@(":@ktop) NB. enrich ktop with % mut 1.05 5% ptok=:>:@(*&0.01) :.mut NB. redefine obverse of ptok gm&.ptok 5 6 13 _12 0 2.04959%
The verb ptok provides a salutary lesson in the power of parentheses. The verb
pet=:>:@*&0.01
means (>:@*)&0.01 and is indistinguishable from ptok when used directly. However in inverse mode, and bearing in mind that conjunctions have long left scope, the rule for the inverse of ptok is
(*&0.01 ^:_1)@(>: ^:_1)
that is (%&0.01 ^:_1)@(<:) , or in plain English subtract one and multiply by 100 (that is, divide by 0.01), which is exactly what ktop does. The computed obverse of pet, however, is a somewhat complicated verb, which in the case of a scalar argument reduces to division by 1.01. The programming lesson is that whereas parentheses may be redundant in the normal operation of a verb, they can sometimes have a profound effect on its obverse.
Kirk Iverson provided a dazzling example of the use of obverse. The problem is to segregate a list of integers, say 4 2 2 4 1 4 8, into boxes with empty boxes for those integers in sequence not present. Boxing like items is achieved by using the vector itself as a key (/.)
k=:4 2 2 4 1 4 8 k</.k ┌─────┬───┬─┬─┐ │4 4 4│2 2│1│8│ └─────┴───┴─┴─┘
Now augment the vector with say i.10
aug=:(i.10)&, aug k 0 1 2 3 4 5 6 7 8 9 4 2 2 4 1 4 8
and finally add an obverse which beheads under box so that the artificially added i.10 is wiped out item by item each from its own box
aug=:(i.10)&, :. (}.&.>)
Finally do the initial box by key under aug which achieves both numerical ordering and also empty boxes where appropriate
</.~&.aug k ┌┬─┬───┬┬─────┬┬┬┬─┬┐ ││1│2 2││4 4 4││││8││ └┴─┴───┴┴─────┴┴┴┴─┴┘
Previous paragraphs raise the question of which verbs have ‘reasonable’ inverses, to which the answer is: quite a lot. First there are self-inverse monadic verbs for which an even number of applications amounts to ‘do nothing’. These are
- arithmetic
+ - -. (not) % %. (matrix divide)
- structural
|. (reverse) |: (transpose) /: (grade up) [ (left) ] (right) and C. (cycle-direct)
(…See Essay #30: Just what do they sell at C&A?)
Next here is a set of monadic verbs which have inverse partners, that is for each of these verbs v^:_1 is equivalent to its partner
- arithmetic
<: and >: | (increment /decrement) |
+: or +~ and -: | (double/halve) |
*: or *~ and %: | (square/square root) |
^ and ^. | (power/logarithm) |
# and #: | (base/anti-base = decode/encode in APL) |
o. and (%&1p1) | (multiply by π/ divide by π ) |
j. and (%&0j1) | (multiply by srqt(-1)/divide by sqrt(-1)) |
+. and j./ | (vector from/to complex no.) |
- structural
< (box) and > (open) |
;~ (reflex-raze) and >@{. (open following head) |
\: (grade-down) and /:@|. (grade-up following reverse) |
,: (itemise) and {. (head) |
". (do) and ": (format) |
There are also families of monadic verb pairs formed by ‘currying’ dyadic verbs with a noun:
+&n and -&n | (add/subtract constant) |
*&n and %&n | (multiply by/divide by constant) |
n&^ and n&^. | (power of n/log to base n) |
n&o. and _n&o. | (for appropriate n, e.g. sin and arcsin) |
n&|. and _n&|. | (shift n left/ shift n right) |
p&|: and (ip&|:) | (ip= inverse permutation applied to transpose) |
The generic property of the inverse i of a monadic verb v is that (i@v) is equivalent to ].
The ‘scans’ of five arithmetic verbs, namely + * % = ~: can be reversed by ^:_1, that is each of these verbs has the property that v/^:_1 is equivalent to ].
Dyadic verbs have potentially two kinds of inverse, left and right. For example the dyadic + has a right inverse function - because a+b-b=a, that is subtraction on the right ‘cancels out’ addition. However dyadic + has no left inverse because there is no function i for which a i a+b = b for all a and b. By the same reasoning minus has a left inverse minus and a right inverse plus. Inverses for dyadic verbs are rarer than for monadics. The following is a list of them
+ | - | * | % | ^ | ^. | = | ~: | |
Left inverse | - | % | ^. | ^ | = | ~: | ||
Right inverse | - | * | = | ~: |
A left inverse i is characterised by the fact that the fork [iv is equivalent to ] and a right inverse by iv] being equivalent to [.
Adverse, like obverse, is used to define a two-sided verb, but now it provides an alternative verb, the one you use ‘in adversity’ when the first one fails. It is unlikely to be an inverse, (although in principle it could be!) If the first verb fails, then the adverse takes over.
Here, for example, is a protection device against ‘index error’
3 4{'ABCDE' DE 3 5{'ABCDE' |index error From=:{ :: ] 3 5 From 'ABCDE' ABCDE
One obvious circumstance in which you might think this could be applied is
div=:% :: 1:
to prevent attempted division by zero but this doesn't work because division by 0 is not an error in J - the result is infinity (_). The only circumstance in which 0 would be delivered is on an attempt to divide characters, or two vectors of unequal lengths, both greater than 1.
Since they connect verbs, obverse and adverse are conjunctions, but unlike the more commonly used conjunctions they define ‘flip-sides’ rather than creating fundamentally new composite verbs. To summarise, an obverse is a user-defined inverse, adverse is the emergency exit to forestall error conditions.
Code Summary
dtb=:({.~i.&' ') :. (,&',') NB. delete trailing blanks frtab=:+/"1@= NB. frequency list convert=:# i.@# NB. inverse of frtab ptok=:>:@(*&0.01) NB. e.g. 5% to 1.05 mut=:,&'%'@(":@ktop) NB. enrich ktop with % ktop=:%&0.01@<: NB. inverse of ptok gm=:(+/%#)&.(^."_) NB. geometric mean From=:{ :: ] NB. from with error trapping aug=:(i.10)&, :. (}.&.>) NB. boxed integers with blanks