Transforms

Python implementation of the Overview/Transforms

Sections

Definition

Formal and Abstract

Functional transforms

Application to history

Partition transforms

Natural converse

Sample converse

Actual converse

Independent converse

Transforms as models

Example - a weather forecast

Definition

Given a histogram $X \in \mathcal{A}$ and a subset of its variables $W \subseteq \mathrm{vars}(X)$, the pair $T = (X,W)$ forms a transform. The Transform type is defined with a pair of a Histogram and a Variable set,

newtype Transform = Transform (Histogram, (Set.Set Variable))

A Transform is constructed from a Histogram and a set of Variable,

histogramsSetVarsTransform :: Histogram -> Set.Set Variable -> Maybe Transform

Consider the deck of cards example,

def lluu(ll):
    return listsSystem([(v,sset(ww)) for (v,ww) in ll])

[suit,rank] = map(VarStr, ["suit","rank"])
[hearts,clubs,diamonds,spades] = map(ValStr, ["hearts","clubs","diamonds","spades"])
[jack,queen,king,ace] = map(ValStr, ["J","Q","K","A"])

uu = lluu([
      (suit, [hearts,clubs,diamonds,spades]),
      (rank, [jack,queen,king,ace] + list(map(ValInt,range(2,10+1))))])

vv = sset([suit, rank])

uu
# {(rank, {A, J, K, Q, 2, 3, 4, 5, 6, 7, 8, 9, 10}), (suit, {clubs, diamonds, hearts, spades})}

vv
# {rank, suit}

aa = unit(cart(uu,vv))

rpln(aall(aa))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, diamonds)}, 1 % 1)
# ({(rank, A), (suit, hearts)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, clubs)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ...
# ({(rank, 9), (suit, hearts)}, 1 % 1)
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, diamonds)}, 1 % 1)
# ({(rank, 10), (suit, hearts)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

A transform can be constructed from a histogram $X$ relating the suit to the colour,

colour = VarStr("colour")
red = ValStr("red")
black = ValStr("black")

xx = llaa([(llss([(suit, u),(colour, w)]),1) for (u,w) in [(hearts, red), (clubs, black), (diamonds, red), (spades, black)]])

rpln(aall(xx))
# ({(colour, black), (suit, clubs)}, 1 % 1)
# ({(colour, black), (suit, spades)}, 1 % 1)
# ({(colour, red), (suit, diamonds)}, 1 % 1)
# ({(colour, red), (suit, hearts)}, 1 % 1)

ww = sset([colour])

trans = histogramsSetVarsTransform

trans(xx,ww)
# ({({(colour, black), (suit, clubs)}, 1 % 1), ({(colour, black), (suit, spades)}, 1 % 1), ({(colour, red), (suit, diamonds)}, 1 % 1), ({(colour, red), (suit, hearts)}, 1 % 1)}, {colour})

The variables, $W$, are the derived variables. The complement $K = \mathrm{vars}(X) \setminus W$ are the underlying variables,

ww
# {colour}

kk = vars(xx) - ww

kk
# {suit}

The set of all transforms is \[ \begin{eqnarray} \mathcal{T} &:=& \{(X,W) : X \in \mathcal{A},~W \subseteq \mathrm{vars}(X)\} \end{eqnarray} \] The transform histogram is $X = \mathrm{his}(T)$. The transform derived is $W = \mathrm{der}(T)$. The transform underlying is $K = \mathrm{und}(T)$,

transformsHistogram :: Transform -> Histogram
transformsUnderlying :: Transform -> Set.Set Variable
transformsDerived :: Transform -> Set.Set Variable

For example,

ttaa = transformsHistogram
und = transformsUnderlying
der = transformsDerived

tt = trans(xx,ww)

ttaa(tt) == xx
# True

und(tt) == kk
# True

der(tt) == ww
# True

The null transform is $(X,\emptyset)$,

histogramsTransformNull :: Histogram -> Transform

For example,

null = histogramsTransformNull

ttaa(null(aa)) == aa
# True

und(null(aa)) == vars(aa)
# True

der(null(aa)) == sset()
# True

The full transform is $(X,\mathrm{vars}(X))$,

histogramsTransformDisjoint :: Histogram -> Transform

For example,

full = histogramsTransformDisjoint

ttaa(full(aa)) == aa
# True

und(full(aa)) == sset()
# True

der(full(aa)) == vars(aa)
# True

Given a histogram $A \in \mathcal{A}$, the multiplication of the histogram, $A$, by the transform $T \in \mathcal{T}$ equals the multiplication of the histogram, $A$, by the transform histogram $X = \mathrm{his}(T)$ followed by the reduction to the derived variables $W = \mathrm{der}(T)$, \[ \begin{eqnarray} A * T~=~A * (X,W) &:=& A * X~\%~W \end{eqnarray} \]

transformsHistogramsApply :: Transform -> Histogram -> Histogram

For example,

def tmul(aa,tt):
    return transformsHistogramsApply(tt,aa)

rpln(aall(tmul(aa,tt)))
# ({(colour, black)}, 26 % 1)
# ({(colour, red)}, 26 % 1)

tmul(aa,tt) == ared(mul(aa,xx),ww)
# True

If the histogram variables are a superset of the underlying variables, $\mathrm{und}(T) \subseteq \mathrm{vars}(A)$,

und(tt).issubset(vars(aa))
# True

then the histogram, $A$, is called the underlying histogram and the multiplication, $A * T$, is called the derived histogram. The derived histogram variables equals the derived variables, $\mathrm{vars}(A*T) = \mathrm{der}(T)$.

If the set of underlying variables of a transform is a proper subset of the set of histogram variables, $K \subset V$, the transform can be expanded by multiplying its histogram by the cartesian histogram of the set of remaining variables, $V \setminus K$. In the deck of cards example, the set of underlying variables, $K$, is a singleton consisting of the suit,

und(tt)
# {suit}

The transform is expanded to the histogram variables, $V$, by multiplying by the cartesian histogram for the rank,

vk = vv - kk

vk
# {rank}

ttv = trans(mul(ttaa(tt),unit(cart(uu,vk))), der(tt))

und(ttv)
# {rank, suit}

und(ttv) == vv
# True

The set of derived variables of the expanded transform is unchanged, so the derived histogram is unchanged,

der(ttv) == der(tt)
# True

tmul(aa,ttv) == tmul(aa,tt)
# True

The application of the null transform of the cartesian is the scalar, $A * (V^{\mathrm{C}},\emptyset) = A \% \emptyset = \mathrm{scalar}(\mathrm{size}(A))$, where $V = \mathrm{vars}(A)$,

vvc = unit(cart(uu,vv))

tmul(aa,null(vvc)) == ared(aa,sset())
# True

The application of the full transform of the cartesian is the histogram, $A * (V^{\mathrm{C}},V) = A \% V = A$,

tmul(aa,full(vvc)) == aa
# True

Formal and Abstract

Given a histogram $A \in \mathcal{A}$ and a transform $T \in \mathcal{T}$, the formal histogram is defined as the independent derived, $A^{\mathrm{X}} * T$. In the case of the deck of cards example, the histogram, $A$, is just the cartesian and is already independent. So the formal histogram equals the derived histogram,

rpln(aall(tmul(ind(aa),tt)))
# ({(colour, black)}, 26 % 1)
# ({(colour, red)}, 26 % 1)

tmul(ind(aa),tt) == tmul(aa,tt)
# True

Consider a transform $T’$ with two derived variables constructed on two underlying variables as follows,

tt1 = trans(cdaa([[1,1,1,2],[1,2,1,1],[1,3,1,1],[2,1,2,1],[2,2,2,2],[2,3,2,1],[3,1,2,1],[3,2,2,1],[3,3,1,2]]), sset([VarInt(3), VarInt(4)]))

rpln(aall(ttaa(tt1)))
# ({(1, 1), (2, 1), (3, 1), (4, 2)}, 1 % 1)
# ({(1, 1), (2, 2), (3, 1), (4, 1)}, 1 % 1)
# ({(1, 1), (2, 3), (3, 1), (4, 1)}, 1 % 1)
# ({(1, 2), (2, 1), (3, 2), (4, 1)}, 1 % 1)
# ({(1, 2), (2, 2), (3, 2), (4, 2)}, 1 % 1)
# ({(1, 2), (2, 3), (3, 2), (4, 1)}, 1 % 1)
# ({(1, 3), (2, 1), (3, 2), (4, 1)}, 1 % 1)
# ({(1, 3), (2, 2), (3, 2), (4, 1)}, 1 % 1)
# ({(1, 3), (2, 3), (3, 1), (4, 2)}, 1 % 1)

und(tt1)
# {1, 2}

der(tt1)
# {3, 4}

rpln(aall(tmul(regcart(3,2),tt1)))
# ({(3, 1), (4, 1)}, 2 % 1)
# ({(3, 1), (4, 2)}, 2 % 1)
# ({(3, 2), (4, 1)}, 4 % 1)
# ({(3, 2), (4, 2)}, 1 % 1)

rpln(aall(tmul(regdiag(3,2),tt1)))
# ({(3, 1), (4, 2)}, 2 % 1)
# ({(3, 2), (4, 2)}, 1 % 1)

Now the formal histogram of a regular diagonal underlying differs from the derived histogram,

rpln(aall(tmul(ind(regdiag(3,2)),tt1)))
# ({(3, 1), (4, 1)}, 2 % 3)
# ({(3, 1), (4, 2)}, 2 % 3)
# ({(3, 2), (4, 1)}, 4 % 3)
# ({(3, 2), (4, 2)}, 1 % 3)

tmul(ind(regdiag(3,2)),tt1) == tmul(regdiag(3,2),tt1)
# False

tmul(ind(regcart(3,2)),tt1) == tmul(regcart(3,2),tt1)
# True

The abstract histogram is defined as the derived independent, $(A * T)^{\mathrm{X}}$. In the case of the deck of cards example, the transform, $T$, has only one derived variable and so the derived histogram is already independent,

rpln(aall(ind(tmul(aa,tt))))
# ({(colour, black)}, 26 % 1)
# ({(colour, red)}, 26 % 1)

ind(tmul(aa,tt)) == tmul(aa,tt)
# True

In the case of transform $T’$, however, the abstract histogram of a regular cartesian underlying differs from the derived histogram,

rpln(aall(ind(tmul(regcart(3,2),tt1))))
# ({(3, 1), (4, 1)}, 8 % 3)
# ({(3, 1), (4, 2)}, 4 % 3)
# ({(3, 2), (4, 1)}, 10 % 3)
# ({(3, 2), (4, 2)}, 5 % 3)

ind(tmul(regcart(3,2),tt1)) == tmul(regcart(3,2),tt1)
# False

ind(tmul(regdiag(3,2),tt1)) == tmul(regdiag(3,2),tt1)
# True

In the case where the formal and abstract are equal, $A^{\mathrm{X}} * T = (A * T)^{\mathrm{X}}$, the abstract equals the independent abstract, $(A * T)^{\mathrm{X}} = A^{\mathrm{X}} * T = (A^{\mathrm{X}} * T)^{\mathrm{X}}$, and so only depends on the independent, $A^{\mathrm{X}}$, not on the histogram, $A$. The formal equals the formal independent, $A^{\mathrm{X}} * T = (A * T)^{\mathrm{X}} = (A^{\mathrm{X}} * T)^{\mathrm{X}}$, and so is itself independent. For example, when the transform $T’$ has only one derived variable and varies with only one of the underlying variables,

tt1 = trans(cdaa([[1,1,1],[1,2,1],[1,3,1],[2,1,2],[2,2,2],[2,3,2],[3,1,2],[3,2,2],[3,3,2]]), sset([VarInt(3)]))

rpln(aall(ttaa(tt1)))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 1)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 1)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 1)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 1)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 3), (3, 2)}, 1 % 1)

rpln(aall(tmul(regcart(3,2),tt1)))
# ({(3, 1)}, 3 % 1)
# ({(3, 2)}, 6 % 1)

tmul(ind(regcart(3,2)),tt1) == ind(tmul(regcart(3,2),tt1))
# True

rpln(aall(tmul(regdiag(3,2),tt1)))
# ({(3, 1)}, 1 % 1)
# ({(3, 2)}, 2 % 1)

tmul(ind(regdiag(3,2)),tt1) == ind(tmul(regdiag(3,2),tt1))
# True

In the case where $T’$ varies with both of the underlying variables, formal-abstract equivalence holds only for the cartesian,

tt1 = trans(cdaa([[1,1,1],[1,2,1],[1,3,1],[2,1,2],[2,2,2],[2,3,2],[3,1,2],[3,2,2],[3,3,1]]), sset([VarInt(3)]))

rpln(aall(ttaa(tt1)))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 1)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 1)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 1)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 1)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 1)

tmul(ind(regcart(3,2)),tt1) == ind(tmul(regcart(3,2),tt1))
# True

tmul(ind(regdiag(3,2)),tt1) == ind(tmul(regdiag(3,2),tt1))
# False

Functional transforms

A transform $T \in \mathcal{T}$ is functional if there is a causal relation between the underlying variables $K = \mathrm{und}(T)$ and the derived variables $W = \mathrm{der}(T)$, \[ \begin{eqnarray} \mathrm{split}(K,X^{\mathrm{FS}}) &\in& K^{\mathrm{CS}} \to W^{\mathrm{CS}} \end{eqnarray} \] where $X=\mathrm{his}(T)$. In the deck of cards example,

xx == ttaa(tt)
# True

rpln(aall(xx))
# ({(colour, black), (suit, clubs)}, 1 % 1)
# ({(colour, black), (suit, spades)}, 1 % 1)
# ({(colour, red), (suit, diamonds)}, 1 % 1)
# ({(colour, red), (suit, hearts)}, 1 % 1)


kk
# {suit}

ww
# {colour}

ssplit = setVarsSetStatesSplit 

rpln(ssplit(kk,(states(xx))))
# ({(suit, clubs)}, {(colour, black)})
# ({(suit, diamonds)}, {(colour, red)})
# ({(suit, hearts)}, {(colour, red)})
# ({(suit, spades)}, {(colour, black)})


iscausal = histogramsIsCausal 

iscausal(xx)
# True

The expanded transform is still causal,

rpln(ssplit(vv,(states(ttaa(ttv)))))
# ({(rank, A), (suit, clubs)}, {(colour, black)})
# ({(rank, A), (suit, diamonds)}, {(colour, red)})
# ({(rank, A), (suit, hearts)}, {(colour, red)})
# ({(rank, A), (suit, spades)}, {(colour, black)})
# ({(rank, J), (suit, clubs)}, {(colour, black)})
# ({(rank, J), (suit, diamonds)}, {(colour, red)})
# ...
# ({(rank, 9), (suit, hearts)}, {(colour, red)})
# ({(rank, 9), (suit, spades)}, {(colour, black)})
# ({(rank, 10), (suit, clubs)}, {(colour, black)})
# ({(rank, 10), (suit, diamonds)}, {(colour, red)})
# ({(rank, 10), (suit, hearts)}, {(colour, red)})
# ({(rank, 10), (suit, spades)}, {(colour, black)})

iscausal(ttaa(ttv))
# True

The set of functional transforms $\mathcal{T}_{\mathrm{f}} \subset \mathcal{T}$ is the subset of all transforms that are causal.

A functional transform $T \in \mathcal{T}_{\mathrm{f}}$ has an inverse, \[ \begin{eqnarray} T^{-1} &:=& \{((S\%K,c), S\%W) : (S,c) \in X\}^{-1} \end{eqnarray} \]

transformsInverse :: Transform -> Map.Map State Histogram

For example,

inv = transformsInverse

rpln(inv(tt))
# ({(colour, black)}, {({(suit, clubs)}, 1 % 1), ({(suit, spades)}, 1 % 1)})
# ({(colour, red)}, {({(suit, diamonds)}, 1 % 1), ({(suit, hearts)}, 1 % 1)})

rpln(inv(ttv))
# ({(colour, black)}, {({(rank, A), (suit, clubs)}, 1 % 1), ..., ({(rank, 10), (suit, spades)}, 1 % 1)})
# ({(colour, red)}, {({(rank, A), (suit, diamonds)}, 1 % 1), ..., ({(rank, 10), (suit, hearts)}, 1 % 1)})

A transform $T$ is one functional in system $U$ if the reduction of the transform histogram to the underlying variables equals the cartesian histogram, $X\%K = K^{\mathrm{C}}$,

ared(xx,kk) == unit(cart(uu,kk))
# True

ared(ttaa(ttv),vv) == unit(cart(uu,vv))
# True

So the causal relation is a derived state valued left total function of underlying state, $\mathrm{split}(K,X^{\mathrm{S}}) \in K^{\mathrm{CS}} :\to W^{\mathrm{CS}}$. The set of one functional transforms $\mathcal{T}_{U,\mathrm{f},1} \subset \mathcal{T}_{\mathrm{f}}$ is \[ \begin{eqnarray} \mathcal{T}_{U,\mathrm{f},1} &=& \{ (\{(S \cup R,1) : (S,R) \in Q\},W) : \\ &&\hspace{5em}K,W \subseteq \mathrm{vars}(U),~K \cap W = \emptyset, ~Q \in K^{\mathrm{CS}} :\to W^{\mathrm{CS}}\} \end{eqnarray} \] The application of a one functional transform to an underlying histogram preserves the size, $\mathrm{size}(A * T) = \mathrm{size}(A)$,

size(tmul(aa,tt)) == size(aa)
# True

size(tmul(aa,ttv)) == size(aa)
# True

The one functional transform inverse is a unit component valued function of derived state, $T^{-1} \in W^{\mathrm{CS}} \to \mathrm{P}(K^{\mathrm{C}})$. That is, the range of the inverse corresponds to a partition of the cartesian states into components, $\mathrm{ran}(T^{-1}) \in \mathrm{B}(K^{\mathrm{C}})$,

[(ss,cc),(rr,dd)] = list(inv(tt).items())

rpln(aall(cc))
# ({(suit, clubs)}, 1 % 1)
# ({(suit, spades)}, 1 % 1)

rpln(aall(dd))
# ({(suit, diamonds)}, 1 % 1)
# ({(suit, hearts)}, 1 % 1)

add(cc,dd) == unit(cart(uu,kk))
# True

and

[(ss,cc),(rr,dd)] = list(inv(ttv).items())

rpln(aall(cc))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, clubs)}, 1 % 1)
# ...
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

rpln(aall(dd))
# ({(rank, A), (suit, diamonds)}, 1 % 1)
# ({(rank, A), (suit, hearts)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ...
# ({(rank, 9), (suit, hearts)}, 1 % 1)
# ({(rank, 10), (suit, diamonds)}, 1 % 1)
# ({(rank, 10), (suit, hearts)}, 1 % 1)

add(cc,dd) == unit(cart(uu,vv))
# True

The application of a one functional transform $T$ to its underlying cartesian $K^{\mathrm{C}}$ is the component cardinality histogram, $K^{\mathrm{C}} * T = \{(R,|C|) : (R,C) \in T^{-1}\}$,

rpln(aall(tmul(unit(cart(uu,kk)),tt)))
# ({(colour, black)}, 2 % 1)
# ({(colour, red)}, 2 % 1)

rpln(aall(tmul(unit(cart(uu,vv)),ttv)))
# ({(colour, black)}, 26 % 1)
# ({(colour, red)}, 26 % 1)

The effective cartesian derived volume is less than or equal to the derived volume, $|(K^{\mathrm{C}} * T)^{\mathrm{F}}| = |T^{-1}| \leq |W^{\mathrm{C}}|$,

len(states(eff(tmul(unit(cart(uu,kk)),tt))))
# 2

len(states(eff(tmul(unit(cart(uu,vv)),ttv))))
# 2

Application to history

A one functional transform $T \in \mathcal{T}_{U,\mathrm{f},1}$ may be applied to a history $H \in \mathcal{H}$ in the underlying variables of the transform, $\mathrm{vars}(H) \supseteq \mathrm{und}(T)$, to construct a derived history, \[ \begin{eqnarray} H * T &:=& \{(x,R) : (x,S) \in H,~\{R\} = (\{S\}^{\mathrm{U}} * T)^{\mathrm{FS}}\} \end{eqnarray} \] The size is unchanged, $|H * T| = |H|$, and the event identifiers are conserved, $\mathrm{dom}(H * T) = \mathrm{dom}(H)$.

transformsHistoriesApply :: Transform -> History -> History

For example,

llhh = listsHistory  
hhll = historyToList

hh = llhh([(IdInt(i+1),ss) for (i,ss) in enumerate(cart(uu, vv))])

rpln(hhll(hh))
# (1, {(rank, A), (suit, clubs)})
# (2, {(rank, A), (suit, diamonds)})
# (3, {(rank, A), (suit, hearts)})
# (4, {(rank, A), (suit, spades)})
# (5, {(rank, J), (suit, clubs)})
# (6, {(rank, J), (suit, diamonds)})
# ...
# (47, {(rank, 9), (suit, hearts)})
# (48, {(rank, 9), (suit, spades)})
# (49, {(rank, 10), (suit, clubs)})
# (50, {(rank, 10), (suit, diamonds)})
# (51, {(rank, 10), (suit, hearts)})
# (52, {(rank, 10), (suit, spades)})

def htmul(hh,tt):
    return transformsHistoriesApply(tt,hh)

rpln(hhll(htmul(hh,tt)))
# (1, {(colour, black)})
# (2, {(colour, red)})
# (3, {(colour, red)})
# (4, {(colour, black)})
# (5, {(colour, black)})
# (6, {(colour, red)})
# ...
# (47, {(colour, red)})
# (48, {(colour, black)})
# (49, {(colour, black)})
# (50, {(colour, red)})
# (51, {(colour, red)})
# (52, {(colour, black)})

Partition transforms

Given a partition $P \in \mathrm{B}(V^{\mathrm{CS}})$ of the cartesian states of variables $V$, a one functional transform can be constructed. The partition transform is \[ \begin{eqnarray} P^{\mathrm{T}} &:=& (\{(S \cup \{(P,C)\}, 1) : C \in P,~S \in C \}, \{P\}) \end{eqnarray} \]

partitionsTransformVarPartition :: Partition -> Transform

The set of derived variables of the partition transform is a singleton of the partition variable, $\mathrm{der}(P^{\mathrm{T}}) = \{P\}$. The derived volume is the component cardinality, $|\{P\}^{\mathrm{C}}| = |P|$. The underlying variables are the given variables, $\mathrm{und}(P^{\mathrm{T}}) = V$. For example, consider a partition of the deck of cards,

qqpp = setComponentsPartition
ppqq = partitionsSetComponent

c = sset(list(states(vvc))[0:13])

d = sset(list(states(vvc))[13:])

pp = qqpp(sset([c,d]))

len(ppqq(pp))
# 2

[len(ee) for ee in ppqq(pp)]
# [13, 39]

pptt = partitionsTransformVarPartition 

und(pptt(pp))
# {rank, suit}

rpln(aall(ared(ttaa(pptt(pp)),und(pptt(pp)))))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, diamonds)}, 1 % 1)
# ({(rank, A), (suit, hearts)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, clubs)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ...
# ({(rank, 9), (suit, hearts)}, 1 % 1)
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, diamonds)}, 1 % 1)
# ({(rank, 10), (suit, hearts)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

der(pptt(pp)) == sset([VarPartition(pp)])
# True

[q for (ss,q) in aall(tmul(aa,pptt(pp)))]
# [13 % 1, 39 % 1]

The expanded transform in the deck of cards example partitions the cartesian set of states,

[(ss,cc),(rr,dd)] = list(inv(ttv).items())

pp = qqpp(sset([states(cc),states(dd)]))

len(ppqq(pp))
# 2

[len(ee) for ee in ppqq(pp)]
# [26, 26]

und(pptt(pp))
# {rank, suit}

rpln(aall(ared(ttaa(pptt(pp)),und(pptt(pp)))))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, diamonds)}, 1 % 1)
# ({(rank, A), (suit, hearts)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, clubs)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ...
# ({(rank, 9), (suit, hearts)}, 1 % 1)
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, diamonds)}, 1 % 1)
# ({(rank, 10), (suit, hearts)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

der(pptt(pp)) == sset([VarPartition(pp)])
# True

[q for (ss,q) in aall(tmul(aa,pptt(pp)))]
# [26 % 1, 26 % 1]

The unary partition transform is $T_{\mathrm{u}} = \{V^{\mathrm{CS}}\}^{\mathrm{T}}$,

unary = systemsSetVarsPartitionUnary

uu1 = sysreg(2,2)

pp = unary(uu1,uvars(uu1))

len(ppqq(pp))
# 1

[len(ee) for ee in ppqq(pp)]
# [4]

und(pptt(pp))
# {1, 2}

der(pptt(pp))
# { { { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} } } }

rpln(aall(ared(ttaa(pptt(pp)),und(pptt(pp)))))
# ({(1, 1), (2, 1)}, 1 % 1)
# ({(1, 1), (2, 2)}, 1 % 1)
# ({(1, 2), (2, 1)}, 1 % 1)
# ({(1, 2), (2, 2)}, 1 % 1)

rpln(aall(ttaa(pptt(pp))))
# ({(1, 1), (2, 1), ({ { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} } }, { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} })}, 1 % 1)
# ({(1, 1), (2, 2), ({ { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} } }, { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} })}, 1 % 1)
# ({(1, 2), (2, 1), ({ { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} } }, { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} })}, 1 % 1)
# ({(1, 2), (2, 2), ({ { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} } }, { {(1, 1), (2, 1)}, {(1, 1), (2, 2)}, {(1, 2), (2, 1)}, {(1, 2), (2, 2)} })}, 1 % 1)

The self partition transform is $T_{\mathrm{s}} = V^{\mathrm{CS}\{\}\mathrm{T}}$,

self = systemsSetVarsPartitionSelf

uu1 = sysreg(2,2)

pp = self(uu1,uvars(uu1))

len(ppqq(pp))
# 4

[len(ee) for ee in ppqq(pp)]
# [1, 1, 1, 1]

und(pptt(pp))
# {1, 2}

der(pptt(pp))
# { { { {(1, 1), (2, 1)} }, { {(1, 1), (2, 2)} }, { {(1, 2), (2, 1)} }, { {(1, 2), (2, 2)} } } }

rpln(aall(ared(ttaa(pptt(pp)),und(pptt(pp)))))
# ({(1, 1), (2, 1)}, 1 % 1)
# ({(1, 1), (2, 2)}, 1 % 1)
# ({(1, 2), (2, 1)}, 1 % 1)
# ({(1, 2), (2, 2)}, 1 % 1)

rpln(aall(ttaa(pptt(pp))))
# ({(1, 1), (2, 1), ({ { {(1, 1), (2, 1)} }, { {(1, 1), (2, 2)} }, { {(1, 2), (2, 1)} }, { {(1, 2), (2, 2)} } }, { {(1, 1), (2, 1)} })}, 1 % 1)
# ({(1, 1), (2, 2), ({ { {(1, 1), (2, 1)} }, { {(1, 1), (2, 2)} }, { {(1, 2), (2, 1)} }, { {(1, 2), (2, 2)} } }, { {(1, 1), (2, 2)} })}, 1 % 1)
# ({(1, 2), (2, 1), ({ { {(1, 1), (2, 1)} }, { {(1, 1), (2, 2)} }, { {(1, 2), (2, 1)} }, { {(1, 2), (2, 2)} } }, { {(1, 2), (2, 1)} })}, 1 % 1)
# ({(1, 2), (2, 2), ({ { {(1, 1), (2, 1)} }, { {(1, 1), (2, 2)} }, { {(1, 2), (2, 1)} }, { {(1, 2), (2, 2)} } }, { {(1, 2), (2, 2)} })}, 1 % 1)

Natural converse

Given a one functional transform $T \in \mathcal{T}_{U,\mathrm{f},1}$, the natural converse is \[ \begin{eqnarray} T^{\dagger} &:=& (X/(X\%W),V) \end{eqnarray} \] where $(X,W) = T$ and $V = \mathrm{und}(T)$,

transformsConverseNatural :: Transform -> Transform

In the deck of cards example, the natural converse of the expanded suit-colour transform is

nat = transformsConverseNatural

rpln(aall(ttaa(ttv)))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 1)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 1)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 1)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 1)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 1)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 1)

der(ttv)
# {colour}

und(ttv)
rp $ und ttv
# {rank, suit}

rpln(aall(ttaa(nat(ttv))))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 26)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 26)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 26)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 26)

der(nat(ttv))
# {rank, suit}

und(nat(ttv))
# {colour}

Another example is $T’$,

def cdtt(pp,ll):
    return trans(cdtp(cdaa(ll),pp), sset([VarInt(pp[-1])]))

tt1 = cdtt([1,2,3],[[1,1,1],[1,2,1],[1,3,1],[2,1,2],[2,2,2],[2,3,2],[3,1,2],[3,2,2],[3,3,1]])

rpln(aall(ttaa(tt1)))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 1)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 1)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 1)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 1)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 1)

der(tt1)
# {3}

rpln(aall(ttaa(nat(tt1))))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 4)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 4)

der(nat(tt1))
# {1, 2}

The natural converse may be expressed in terms of components, \[ T^{\dagger}~:=~(\sum_{(R,C) \in T^{-1}} \{R\}^{\mathrm{U}} * \hat{C},~V) \]

def inv(tt):
    return list(transformsInverse(tt).items())

def sunit(ss):
    return setStatesHistogramUnit(sset([ss]))

rpln(inv(ttv))

# ({(colour, black)}, {({(rank, A), (suit, clubs)}, 1 % 1), ..., ({(rank, 10), (suit, spades)}, 1 % 1)})
# ({(colour, red)}, {({(rank, A), (suit, diamonds)}, 1 % 1), ..., ({(rank, 10), (suit, hearts)}, 1 % 1)})

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,mul(sunit(rr),norm(cc)))

rpln(aall(ee))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 26)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 26)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 26)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 26)

rpln(inv(tt1))
# ({(3, 1)}, {({(1, 1), (2, 1)}, 1 % 1), ({(1, 1), (2, 2)}, 1 % 1), ({(1, 1), (2, 3)}, 1 % 1), ({(1, 3), (2, 3)}, 1 % 1)})
# ({(3, 2)}, {({(1, 2), (2, 1)}, 1 % 1), ({(1, 2), (2, 2)}, 1 % 1), ({(1, 2), (2, 3)}, 1 % 1), ({(1, 3), (2, 1)}, 1 % 1), ({(1, 3),(2, 2)}, 1 % 1)})

ee = histogramEmpty()
for (rr,cc) in inv(tt1):
    ee = add(ee,mul(sunit(rr),norm(cc)))

rpln(aall(ee))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 4)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 4)

Given a histogram $A \in \mathcal{A}$ in the underlying variables, $\mathrm{vars}(A) = V$, the naturalisation is the application of the natural converse transform to the derived histogram, $A * T * T^{\dagger}$,

rpln(aall(tmul(tmul(aa,ttv),nat(ttv))))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, diamonds)}, 1 % 1)
# ({(rank, A), (suit, hearts)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, clubs)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ...
# ({(rank, 9), (suit, hearts)}, 1 % 1)
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, diamonds)}, 1 % 1)
# ({(rank, 10), (suit, hearts)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

A histogram is natural when it equals its naturalisation, $A = A * T * T^{\dagger}$, so the deck of cards histogram is natural,

tmul(tmul(aa,ttv),nat(ttv)) == aa
# True

The cartesian is always natural, $V^{\mathrm{C}} = V^{\mathrm{C}} * T * T^{\dagger}$, so $T’$ applied to the cartesian is natural,

rpln(aall(tmul(tmul(regcart(3,2),tt1),nat(tt1))))
# ({(1, 1), (2, 1)}, 1 % 1)
# ({(1, 1), (2, 2)}, 1 % 1)
# ({(1, 1), (2, 3)}, 1 % 1)
# ({(1, 2), (2, 1)}, 1 % 1)
# ({(1, 2), (2, 2)}, 1 % 1)
# ({(1, 2), (2, 3)}, 1 % 1)
# ({(1, 3), (2, 1)}, 1 % 1)
# ({(1, 3), (2, 2)}, 1 % 1)
# ({(1, 3), (2, 3)}, 1 % 1)

tmul(tmul(regcart(3,2),tt1),nat(tt1)) == regcart(3,2)
# True

but $T’$ applied to the diagonal is not,

rpln(aall(tmul(tmul(regdiag(3,2),tt1),nat(tt1))))
# ({(1, 1), (2, 1)}, 1 % 2)
# ({(1, 1), (2, 2)}, 1 % 2)
# ({(1, 1), (2, 3)}, 1 % 2)
# ({(1, 2), (2, 1)}, 1 % 5)
# ({(1, 2), (2, 2)}, 1 % 5)
# ({(1, 2), (2, 3)}, 1 % 5)
# ({(1, 3), (2, 1)}, 1 % 5)
# ({(1, 3), (2, 2)}, 1 % 5)
# ({(1, 3), (2, 3)}, 1 % 2)

tmul(tmul(regdiag(3,2),tt1),nat(tt1)) == regdiag(3,2)
# False

The naturalisation can be rewritten $A * X~\%~W * X~/~(X\%W)~\%~V$,

ared(divide(mul(ared(mul(aa,ttaa(ttv)),der(ttv)),ttaa(ttv)),ared(ttaa(ttv),der(ttv))),vv) == tmul(tmul(aa,ttv),nat(ttv))
# True

The naturalisation is in the underlying variables, $\mathrm{vars}(A * T * T^{\dagger}) = V$,

vars(tmul(tmul(aa,ttv),nat(ttv)))
# {rank, suit}

The size is conserved, $\mathrm{size}(A * T * T^{\dagger}) = \mathrm{size}(A)$,

size(tmul(tmul(aa,ttv),nat(ttv))) == size(aa)
# True

The naturalisation derived equals the derived, $A * T * T^{\dagger} * T = A * T$,

tmul(tmul(tmul(aa,ttv),nat(ttv)),ttv) == tmul(aa,ttv)
# True

The naturalisation equals the sum of the scaled components, \[ \begin{eqnarray} A * T * T^{\dagger} &=& \sum_{(R,C) \in T^{-1}} \mathrm{scalar}( (A * T)_R) * \hat{C} \\ &=& \sum_{(R,C) \in T^{-1}} A * T * \{R\}^{\mathrm{U}} * \hat{C}~\%~V \end{eqnarray} \]

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,mul(scalar(aat(tmul(aa,ttv),rr)),norm(cc)))

tmul(tmul(aa,ttv),nat(ttv)) == ee
# True

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,ared(mul(mul(tmul(aa,ttv),sunit(rr)),norm(cc)),vv))

tmul(tmul(aa,ttv),nat(ttv)) == ee
# True

So each component is uniform, \[ \forall (R,C) \in T^{-1}~(|\mathrm{ran}(A * T * T^{\dagger} * C)| ~=~ 1) \]

isunif = histogramsIsUniform

[isunif(mul(tmul(tmul(aa,ttv),nat(ttv)),cc)) for (rr,cc) in inv(ttv)]
# [True, True]

The naturalisation of the unary partition transform, $T_{\mathrm{u}} = \{V^{\mathrm{CS}}\}^{\mathrm{T}}$, is the sized cartesian, $A * T_{\mathrm{u}} * T_{\mathrm{u}}^{\dagger} = V_z^{\mathrm{C}}$, where $z=\mathrm{size}(A)$,

pptt = partitionsTransformVarPartition 

def unary(uu,vv):
    return pptt(systemsSetVarsPartitionUnary(uu,vv))

tmul(tmul(aa,unary(uu,vv)),nat(unary(uu,vv))) == resize(size(aa),unit(cart(uu,vv)))
# True

The naturalisation of the self partition transform, $T_{\mathrm{s}} = V^{\mathrm{CS}\{\}\mathrm{T}}$, is the histogram, $A * T_{\mathrm{s}} * T_{\mathrm{s}}^{\dagger} = A$,

def self(uu,vv):
    return pptt(systemsSetVarsPartitionSelf(uu,vv))

tmul(tmul(aa,self(uu,vv)),nat(self(uu,vv))) == aa
# True

Sample converse

Given a one functional transform $T \in \mathcal{T}_{U,\mathrm{f},1}$ with underlying variables $V = \mathrm{und}(T)$, and a histogram $A \in \mathcal{A}$ in the same variables, $\mathrm{vars}(A) = V$, the sample converse is \[ \begin{eqnarray} (\hat{A} * X,V) \end{eqnarray} \] where $X = \mathrm{his}(T)$. The sample converse for the deck of cards example is

tta = trans(mul(norm(aa),ttaa(ttv)),vars(aa))

rpln(aall(ttaa(tta)))

rpln $ aall $ ttaa tta
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 52)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 52)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 52)
# ({(colour, black), (rank, J), (suit, spades)}, 1 % 52)
# ({(colour, black), (rank, K), (suit, clubs)}, 1 % 52)
# ({(colour, black), (rank, K), (suit, spades)}, 1 % 52)
# ...
# ({(colour, red), (rank, 8), (suit, diamonds)}, 1 % 52)
# ({(colour, red), (rank, 8), (suit, hearts)}, 1 % 52)
# ({(colour, red), (rank, 9), (suit, diamonds)}, 1 % 52)
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 52)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 52)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 52)

der(tta)
# {rank, suit}

und(tta)
# {colour}

Actual converse

Related to the sample converse, the actual converse is defined as the summed normalised application of the components to the sample histogram, \[ \begin{eqnarray} T^{\odot A} &:=& (\sum_{(R,C) \in T^{-1}} {R}^{\mathrm{U}} * (A * C)^{\wedge},~V) \end{eqnarray} \]

histogramsTransformsConverseActual :: Histogram -> Transform -> Maybe Transform

In the deck of cards example, the actual converse of the expanded suit-colour transform is

def act(tt,aa):
    return histogramsTransformsConverseActual(aa,tt)

rpln(aall(ttaa(act(ttv,aa))))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 26)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 26)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 26)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 26)

der(act(ttv,aa))
# {rank, suit}

und(act(ttv,aa))
# {colour}

Another example is $T’$,

tt1 = cdtt([1,2,3],[[1,1,1],[1,2,1],[1,3,1],[2,1,2],[2,2,2],[2,3,2],[3,1,2],[3,2,2],[3,3,1]])

rpln(aall(ttaa(act(tt1,regcart(3,2)))))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 4)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 4)

der(act(tt1,regcart(3,2)))
# {1, 2}

rpln(aall(ttaa(act(tt1,regdiag(3,2)))))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 2)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 2)

der(act(tt1,regdiag(3,2)))
# {1, 2}

The actual converse may be expressed in terms of components,

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,mul(sunit(rr),norm(mul(aa,cc))))

rpln(aall(ee))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 26)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 26)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 26)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 26)

ee = histogramEmpty()
for (rr,cc) in inv(tt1):
    ee = add(ee,mul(sunit(rr),norm(mul(regcart(3,2),cc))))

rpln(aall(ee))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 2), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 4)
# ({(1, 2), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 2), (2, 3), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 1), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 2), (3, 2)}, 1 % 5)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 4)

ee = histogramEmpty()
for (rr,cc) in inv(tt1):
    ee = add(ee,mul(sunit(rr),norm(mul(regdiag(3,2),cc))))

rpln(aall(ee))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 2)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 2)

The application of the actual converse transform to the derived histogram equals the histogram, $A * T * T^{\odot A} = A$,

tmul(tmul(aa,ttv),act(ttv,aa)) == aa
# True

tmul(tmul(regcart(3,2),tt1),act(tt1,regcart(3,2))) == regcart(3,2)
# True

tmul(tmul(regdiag(3,2),tt1),act(tt1,regdiag(3,2))) == regdiag(3,2)
# True

Independent converse

Given a one functional transform $T \in \mathcal{T}_{U,\mathrm{f},1}$ with underlying variables $V = \mathrm{und}(T)$, and a histogram $A \in \mathcal{A}$ in the same variables, $\mathrm{vars}(A) = V$, the independent converse is defined as the summed normalised independent application of the components to the sample histogram, \[ \begin{eqnarray} T^{\dagger A} &:=& (\sum_{(R,C) \in T^{-1}} \{R\}^{\mathrm{U}} * (A * C)^{\wedge\mathrm{X}},~V) \end{eqnarray} \]

histogramsTransformsConverseIndependent :: Histogram -> Transform -> Maybe Transform

In the deck of cards example, the independent converse of the expanded suit-colour transform is

def idl(tt,aa):
    return histogramsTransformsConverseIndependent(aa,tt)

rpln(aall(ttaa(idl(ttv,aa))))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 26)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 26)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 26)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 26)

der(idl(ttv,aa))
# {rank, suit}

und(idl(ttv,aa))
# {colour}

Another example is $T’$,

tt1 = cdtt([1,2,3],[[1,1,1],[1,2,1],[1,3,1],[2,1,2],[2,2,2],[2,3,2],[3,1,2],[3,2,2],[3,3,1]])

rpln(aall(ttaa(idl(tt1,regcart(3,2)))))
# ({(1, 1), (2, 1), (3, 1)}, 3 % 16)
# ({(1, 1), (2, 2), (3, 1)}, 3 % 16)
# ({(1, 1), (2, 3), (3, 1)}, 3 % 8)
# ({(1, 2), (2, 1), (3, 2)}, 6 % 25)
# ({(1, 2), (2, 2), (3, 2)}, 6 % 25)
# ({(1, 2), (2, 3), (3, 2)}, 3 % 25)
# ({(1, 3), (2, 1), (3, 1)}, 1 % 16)
# ({(1, 3), (2, 1), (3, 2)}, 4 % 25)
# ({(1, 3), (2, 2), (3, 1)}, 1 % 16)
# ({(1, 3), (2, 2), (3, 2)}, 4 % 25)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 8)
# ({(1, 3), (2, 3), (3, 2)}, 2 % 25)

der(idl(tt1,regcart(3,2)))
# {1, 2}

rpln(aall(ttaa(idl(tt1,regdiag(3,2)))))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 4)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 4)

der(idl(tt1,regdiag(3,2)))
# {1, 2}

The independent converse may be expressed in terms of components,

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,mul(sunit(rr),ind(norm(mul(aa,cc)))))

rpln(aall(ee))
# ({(colour, black), (rank, A), (suit, clubs)}, 1 % 26)
# ({(colour, black), (rank, A), (suit, spades)}, 1 % 26)
# ({(colour, black), (rank, J), (suit, clubs)}, 1 % 26)
# ...
# ({(colour, red), (rank, 9), (suit, hearts)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, diamonds)}, 1 % 26)
# ({(colour, red), (rank, 10), (suit, hearts)}, 1 % 26)

ee = histogramEmpty()
for (rr,cc) in inv(tt1):
    ee = add(ee,mul(sunit(rr),ind(norm(mul(regcart(3,2),cc)))))

rpln(aall(ee))
# ({(1, 1), (2, 1), (3, 1)}, 3 % 16)
# ({(1, 1), (2, 2), (3, 1)}, 3 % 16)
# ({(1, 1), (2, 3), (3, 1)}, 3 % 8)
# ({(1, 2), (2, 1), (3, 2)}, 6 % 25)
# ({(1, 2), (2, 2), (3, 2)}, 6 % 25)
# ({(1, 2), (2, 3), (3, 2)}, 3 % 25)
# ({(1, 3), (2, 1), (3, 1)}, 1 % 16)
# ({(1, 3), (2, 1), (3, 2)}, 4 % 25)
# ({(1, 3), (2, 2), (3, 1)}, 1 % 16)
# ({(1, 3), (2, 2), (3, 2)}, 4 % 25)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 8)
# ({(1, 3), (2, 3), (3, 2)}, 2 % 25)

ee = histogramEmpty()
for (rr,cc) in inv(tt1):
    ee = add(ee,mul(sunit(rr),ind(norm(mul(regdiag(3,2),cc)))))

rpln(aall(ee))
# ({(1, 1), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 1), (2, 3), (3, 1)}, 1 % 4)
# ({(1, 2), (2, 2), (3, 2)}, 1 % 1)
# ({(1, 3), (2, 1), (3, 1)}, 1 % 4)
# ({(1, 3), (2, 3), (3, 1)}, 1 % 4)

The idealisation is the application of the independent converse transform to the derived histogram, $A * T * T^{\dagger A}$,

rpln(aall(tmul(tmul(aa,ttv),idl(ttv,aa))))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, diamonds)}, 1 % 1)
# ({(rank, A), (suit, hearts)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, clubs)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ...
# ({(rank, 9), (suit, hearts)}, 1 % 1)
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, diamonds)}, 1 % 1)
# ({(rank, 10), (suit, hearts)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

rpln(aall(tmul(tmul(regcart(3,2),tt1),idl(tt1,regcart(3,2)))))
# ({(1, 1), (2, 1)}, 3 % 4)
# ({(1, 1), (2, 2)}, 3 % 4)
# ({(1, 1), (2, 3)}, 3 % 2)
# ({(1, 2), (2, 1)}, 6 % 5)
# ({(1, 2), (2, 2)}, 6 % 5)
# ({(1, 2), (2, 3)}, 3 % 5)
# ({(1, 3), (2, 1)}, 21 % 20)
# ({(1, 3), (2, 2)}, 21 % 20)
# ({(1, 3), (2, 3)}, 9 % 10)

rpln(aall(tmul(tmul(regdiag(3,2),tt1),idl(tt1,regdiag(3,2)))))
# ({(1, 1), (2, 1)}, 1 % 2)
# ({(1, 1), (2, 3)}, 1 % 2)
# ({(1, 2), (2, 2)}, 1 % 1)
# ({(1, 3), (2, 1)}, 1 % 2)
# ({(1, 3), (2, 3)}, 1 % 2)

A histogram is ideal when it equals its idealisation, $A = A * T * T^{\dagger A}$, so the deck of cards histogram is ideal,

tmul(tmul(aa,ttv),idl(ttv,aa)) == aa
# True

$T’$ applied to the cartesian is not ideal,

tmul(tmul(regcart(3,2),tt1),idl(tt1,regcart(3,2))) == regcart(3,2)
# False

nor is the application to the diagonal,

tmul(tmul(regdiag(3,2),tt1),idl(tt1,regdiag(3,2))) == regdiag(3,2)
# False

The idealisation is in the underlying variables, $\mathrm{vars}(A * T * T^{\dagger A}) = V$,

vars(tmul(tmul(aa,ttv),idl(ttv,aa))) == vv
# True

The size is conserved, $\mathrm{size}(A * T * T^{\dagger A}) = \mathrm{size}(A)$,

size(tmul(tmul(aa,ttv),idl(ttv,aa))) == size(aa)
# True

The idealisation derived equals the derived, $A * T * T^{\dagger A} * T = A * T$,

tmul(tmul(tmul(aa,ttv),idl(ttv,aa)),ttv) == tmul(aa,ttv)
# True

The idealisation equals the sum of the independent components, \[ \begin{eqnarray} A * T * T^{\dagger A} &=& \sum_{(R,C) \in T^{-1}} (A * C)^{\mathrm{X}} \\ &=& \sum_{(R,C) \in T^{-1}} A * T * \{R\}^{\mathrm{U}} * (A * C)^{\wedge\mathrm{X}}~\%~V \end{eqnarray} \]

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,ind(mul(aa,cc)))

tmul(tmul(aa,ttv),idl(ttv,aa)) == ee
# True

ee = histogramEmpty()
for (rr,cc) in inv(ttv):
    ee = add(ee,ared(mul(mul(tmul(aa,ttv),sunit(rr)),norm(ind(mul(aa,cc)))),vv))

tmul(tmul(aa,ttv),idl(ttv,aa)) == ee
# True

So each component is independent, \[ \forall (R,C) \in T^{-1}~(A * T * T^{\dagger A} * C = (A * T * T^{\dagger A} * C)^{\mathrm{X}} = (A * C)^{\mathrm{X}}) \]

[mul(tmul(tmul(aa,ttv),idl(ttv,aa)),cc) == ind(mul(aa,cc)) for (rr,cc) in inv(ttv)]
# [True, True]

The idealisation of the unary partition transform, $T_{\mathrm{u}} = \{V^{\mathrm{CS}}\}^{\mathrm{T}}$, is the sized cartesian, $A * T_{\mathrm{u}} * T_{\mathrm{u}}^{\dagger A} = V_z^{\mathrm{C}}$,

pptt = partitionsTransformVarPartition 

def unary(uu,vv):
    return pptt(systemsSetVarsPartitionUnary(uu,vv))

tmul(tmul(aa,unary(uu,vv)),idl(unary(uu,vv),aa)) == resize(size(aa),unit(cart(uu,vv)))
# True

The idealisation of the self partition transform, $T_{\mathrm{s}} = V^{\mathrm{CS}\{\}\mathrm{T}}$, is the histogram, $A * T_{\mathrm{s}} * T_{\mathrm{s}}^{\dagger A} = A$,

def self(uu,vv):
    return pptt(systemsSetVarsPartitionSelf(uu,vv))

tmul(tmul(aa,self(uu,vv)),idl(self(uu,vv),aa)) == aa
# True

The idealisation independent equals the independent, $(A * T * T^{\dagger A})^{\mathrm{X}} = A^{\mathrm{X}}$,

ind(tmul(tmul(aa,ttv),idl(ttv,aa))) == ind(aa)
# True

ind(tmul(tmul(regcart(3,2),tt1),idl(tt1,regcart(3,2)))) == ind(regcart(3,2))
# True

ind(tmul(tmul(regdiag(3,2),tt1),idl(tt1,regdiag(3,2)))) == ind(regdiag(3,2))
# True

The idealisation formal equals the formal, $(A * T * T^{\dagger A})^{\mathrm{X}} * T = A^{\mathrm{X}} * T$,

tmul(ind(tmul(tmul(aa,ttv),idl(ttv,aa))),ttv) == tmul(ind(aa),ttv)
# True

tmul(ind(tmul(tmul(regcart(3,2),tt1),idl(tt1,regcart(3,2)))),tt1) == tmul(ind(regcart(3,2)),tt1)
# True

tmul(ind(tmul(tmul(regdiag(3,2),tt1),idl(tt1,regdiag(3,2)))),tt1) == tmul(ind(regdiag(3,2)),tt1)
# True

Transforms as models

The sense in which a transform is a simple model can be seen by considering queries on a sample histogram. Let histogram $A$ have a set of variables $V = \mathrm{vars}(A)$ which is partitioned into query variables $K \subset V$ and label variables $V \setminus K$. Let $T = (X,W)$ be a one functional transform having underlying variables equal to the query variables, $\mathrm{und}(T) = K$. Given a query state $Q \in K^{\mathrm{CS}}$ that may be ineffective in the sample, $Q \notin (A\%K)^{\mathrm{FS}}$, but is effective in the sample derived, $R \in (A * T)^{\mathrm{FS}}$ where $\{R\} = (\{Q\}^{\mathrm{U}} * T)^{\mathrm{FS}}$, the probability histogram for the label is \[ \begin{eqnarray} (\{Q\}^{\mathrm{U}} * T * (\hat{A} * X,V))^{\wedge}~\%~(V \setminus K) &\in& \mathcal{A} \cap \mathcal{P} \end{eqnarray} \] where the sample converse transform is $(\hat{A} * X,V)$. This can be expressed more simply in terms of the actual converse, \[ \begin{eqnarray} \{Q\}^{\mathrm{U}} * T * T^{\odot A}~\%~(V \setminus K) &\in& \mathcal{A} \cap \mathcal{P} \end{eqnarray} \] The query of the sample via model can also be written without the transforms, $(\{Q\}^{\mathrm{U}} * X~\%~W * X * A)^{\wedge}~\%~(V \setminus K)$. In the deck of cards example, the model of the colours of the suits does not tell us anything about the rank given the suit in the case where the histogram is the entire deck,

qq = unit(sset([llss([(suit,clubs)])]))

vk = sset([rank])

rpln(aall(norm(ared(mul(mul(tmul(qq,tt),xx),aa),vk))))
# ({(rank, A)}, 1 % 13)
# ({(rank, J)}, 1 % 13)
# ({(rank, K)}, 1 % 13)
# ({(rank, Q)}, 1 % 13)
# ({(rank, 2)}, 1 % 13)
# ({(rank, 3)}, 1 % 13)
# ({(rank, 4)}, 1 % 13)
# ({(rank, 5)}, 1 % 13)
# ({(rank, 6)}, 1 % 13)
# ({(rank, 7)}, 1 % 13)
# ({(rank, 8)}, 1 % 13)
# ({(rank, 9)}, 1 % 13)
# ({(rank, 10)}, 1 % 13)

If, however, we consider a game of cards which has a special deck such that spades and clubs are pip cards and hearts and diamonds are face cards, the suit and the rank are no longer independent,

bb = unit(sset(
      [llss([(suit,s),(rank,r)]) for s in [spades,clubs] for r in [ace] + list(map(ValInt,range(2,10+1)))] +
      [llss([(suit,s),(rank,r)]) for s in [hearts,diamonds] for r in [jack,queen,king]]))

rpln(aall(bb))
# ({(rank, A), (suit, clubs)}, 1 % 1)
# ({(rank, A), (suit, spades)}, 1 % 1)
# ({(rank, J), (suit, diamonds)}, 1 % 1)
# ({(rank, J), (suit, hearts)}, 1 % 1)
# ({(rank, K), (suit, diamonds)}, 1 % 1)
# ({(rank, K), (suit, hearts)}, 1 % 1)
# ({(rank, Q), (suit, diamonds)}, 1 % 1)
# ({(rank, Q), (suit, hearts)}, 1 % 1)
# ({(rank, 2), (suit, clubs)}, 1 % 1)
# ({(rank, 2), (suit, spades)}, 1 % 1)
# ({(rank, 3), (suit, clubs)}, 1 % 1)
# ({(rank, 3), (suit, spades)}, 1 % 1)
# ({(rank, 4), (suit, clubs)}, 1 % 1)
# ({(rank, 4), (suit, spades)}, 1 % 1)
# ({(rank, 5), (suit, clubs)}, 1 % 1)
# ({(rank, 5), (suit, spades)}, 1 % 1)
# ({(rank, 6), (suit, clubs)}, 1 % 1)
# ({(rank, 6), (suit, spades)}, 1 % 1)
# ({(rank, 7), (suit, clubs)}, 1 % 1)
# ({(rank, 7), (suit, spades)}, 1 % 1)
# ({(rank, 8), (suit, clubs)}, 1 % 1)
# ({(rank, 8), (suit, spades)}, 1 % 1)
# ({(rank, 9), (suit, clubs)}, 1 % 1)
# ({(rank, 9), (suit, spades)}, 1 % 1)
# ({(rank, 10), (suit, clubs)}, 1 % 1)
# ({(rank, 10), (suit, spades)}, 1 % 1)

algn(bb)
# 4.502579806192693

Now our model aligns the suit to the rank via colour, so a query on clubs is always a pip card,

rpln(aall(norm(ared(mul(mul(tmul(qq,tt),xx),bb),vk))))
# ({(rank, A)}, 1 % 10)
# ({(rank, 2)}, 1 % 10)
# ({(rank, 3)}, 1 % 10)
# ({(rank, 4)}, 1 % 10)
# ({(rank, 5)}, 1 % 10)
# ({(rank, 6)}, 1 % 10)
# ({(rank, 7)}, 1 % 10)
# ({(rank, 8)}, 1 % 10)
# ({(rank, 9)}, 1 % 10)
# ({(rank, 10)}, 1 % 10)

A query on hearts is always a face card,

qq = unit(sset([llss([(suit,hearts)])]))

rpln(aall(norm(ared(mul(mul(tmul(qq,tt),xx),bb),vk))))
# ({(rank, J)}, 1 % 3)
# ({(rank, K)}, 1 % 3)
# ({(rank, Q)}, 1 % 3)

Of course, in this example the model is not very interesting because we can simply query the sample directly,

rpln(aall(norm(ared(mul(qq,bb),vk))))
# ({(rank, J)}, 1 % 3)
# ({(rank, K)}, 1 % 3)
# ({(rank, Q)}, 1 % 3)

Usually models are more useful when the size of the sample is much smaller than the underlying volume, $z \ll v$, where $z = \mathrm{size}(A)$ and $v = |V^{\mathrm{C}}|$, but not the derived volume, $z \ge w$, where $w = |W^{\mathrm{C}}|$. In these cases the sample itself does not contain the query, $\{Q\}^{\mathrm{U}} * A = \emptyset$, but the sample derived does contain the query derived, $\{R\}^{\mathrm{U}} * (A * T) \neq \emptyset$, and so the resultant labels are those of the corresponding effective component, $A * C~\%~(V \setminus K)$, where $(R,C) \in T^{-1}$.

Example - a weather forecast

Some of the concepts above regarding transforms can be demonstrated with the sample of some weather measurements created in States, histories and histograms,

def lluu(ll):
    return listsSystem([(v,sset(ww)) for (v,ww) in ll])

def llhh(vv,ev):
    return listsHistory([(IdInt(i), llss(zip(vv,ll))) for (i,ll) in ev])

def red(aa,ll):
    return setVarsHistogramsReduce(sset(ll),aa)

def ssplit(ll,aa):
    return setVarsSetStatesSplit(sset(ll),states(aa))


[pressure,cloud,wind,rain] = map(VarStr,["pressure","cloud","wind","rain"])

[low,medium,high,none,light,heavy,strong] = map(ValStr,["low","medium","high","none","light","heavy","strong"])


uu = lluu([
      (pressure, [low,medium,high]),
      (cloud,    [none,light,heavy]),
      (wind,     [none,light,strong]),
      (rain,     [none,light,heavy])])

vv = uvars(uu)

hh = llhh([pressure,cloud,wind,rain],[
      (1,[high,none,none,none]),
      (2,[medium,light,none,light]),
      (3,[high,none,light,none]),
      (4,[low,heavy,strong,heavy]),
      (5,[low,none,light,light]),
      (6,[medium,none,light,light]),
      (7,[low,heavy,light,heavy]),
      (8,[high,none,light,none]),
      (9,[medium,light,strong,heavy]),
      (10,[medium,light,light,light]),
      (11,[high,light,light,heavy]),
      (12,[medium,none,none,none]),
      (13,[medium,light,none,none]),
      (14,[high,light,strong,light]),
      (15,[medium,none,light,light]),
      (16,[low,heavy,strong,heavy]),
      (17,[low,heavy,light,heavy]),
      (18,[high,none,none,none]),
      (19,[low,light,none,light]),
      (20,[high,none,none,none])])

aa = hhaa(hh)

uu
# {(cloud, {heavy, light, none}), (pressure, {high, low, medium}), (rain, {heavy, light, none}), (wind, {light, none, strong})}

vv
# {cloud, pressure, rain, wind}

rpln(aall(aa))
# ({(cloud, heavy), (pressure, low), (rain, heavy), (wind, light)}, 2 % 1)
# ({(cloud, heavy), (pressure, low), (rain, heavy), (wind, strong)}, 2 % 1)
# ({(cloud, light), (pressure, high), (rain, heavy), (wind, light)}, 1 % 1)
# ({(cloud, light), (pressure, high), (rain, light), (wind, strong)}, 1 % 1)
# ({(cloud, light), (pressure, low), (rain, light), (wind, none)}, 1 % 1)
# ({(cloud, light), (pressure, medium), (rain, heavy), (wind, strong)}, 1 % 1)
# ({(cloud, light), (pressure, medium), (rain, light), (wind, light)}, 1 % 1)
# ({(cloud, light), (pressure, medium), (rain, light), (wind, none)}, 1 % 1)
# ({(cloud, light), (pressure, medium), (rain, none), (wind, none)}, 1 % 1)
# ({(cloud, none), (pressure, high), (rain, none), (wind, light)}, 2 % 1)
# ({(cloud, none), (pressure, high), (rain, none), (wind, none)}, 3 % 1)
# ({(cloud, none), (pressure, low), (rain, light), (wind, light)}, 1 % 1)
# ({(cloud, none), (pressure, medium), (rain, light), (wind, light)}, 2 % 1)
# ({(cloud, none), (pressure, medium), (rain, none), (wind, none)}, 1 % 1)

size(aa)
# 20 % 1

Consider the case where we know the pressure, cloud and wind, and wish to predict the rain. That is, the singleton set of rain is set of the label variables, $V \setminus K$, and pressure, cloud and wind together form the query variables, $K$.

In Entropy and alignment the alignments of various reductions were calculated,

algn(resize(20,regdiag(3,4)))
# 31.485060233928998

algn(aa)
# 11.85085227502473

algn(red(aa,[pressure,rain]))
# 4.278766678519384

algn(red(aa,[cloud,rain]))
# 6.4150379630063465

algn(red(aa,[wind,rain]))
# 3.930131313218345

algn(red(aa,[cloud,wind,rain]))
# 8.935048311238008

We can see that pressure and rain are aligned but not causal,

algn(red(aa,[pressure,rain]))
# 4.278766678519384

rpln(ssplit([pressure],red(aa,[pressure,rain])))
# ({(pressure, high)}, {(rain, heavy)})
# ({(pressure, high)}, {(rain, light)})
# ({(pressure, high)}, {(rain, none)})
# ({(pressure, low)}, {(rain, heavy)})
# ({(pressure, low)}, {(rain, light)})
# ({(pressure, medium)}, {(rain, heavy)})
# ({(pressure, medium)}, {(rain, light)})
# ({(pressure, medium)}, {(rain, none)})

histogramsIsCausal(red(aa,[pressure,rain]))
# False

cloud and rain are more aligned,

algn(red(aa,[cloud,rain]))
# 6.4150379630063465

rpln(ssplit([cloud],red(aa,[cloud,rain])))
# ({(cloud, heavy)}, {(rain, heavy)})
# ({(cloud, light)}, {(rain, heavy)})
# ({(cloud, light)}, {(rain, light)})
# ({(cloud, light)}, {(rain, none)})
# ({(cloud, none)}, {(rain, light)})
# ({(cloud, none)}, {(rain, none)})

but cloud, wind and rain are still more aligned,

algn(red(aa,[cloud,wind,rain]))
# 8.935048311238008

rpln(ssplit([cloud,wind],red(aa,[cloud,wind,rain])))
# ({(cloud, heavy), (wind, light)}, {(rain, heavy)})
# ({(cloud, heavy), (wind, strong)}, {(rain, heavy)})
# ({(cloud, light), (wind, light)}, {(rain, heavy)})
# ({(cloud, light), (wind, light)}, {(rain, light)})
# ({(cloud, light), (wind, none)}, {(rain, light)})
# ({(cloud, light), (wind, none)}, {(rain, none)})
# ({(cloud, light), (wind, strong)}, {(rain, heavy)})
# ({(cloud, light), (wind, strong)}, {(rain, light)})
# ({(cloud, none), (wind, light)}, {(rain, light)})
# ({(cloud, none), (wind, light)}, {(rain, none)})
# ({(cloud, none), (wind, none)}, {(rain, none)})

histogramsIsCausal(red(aa,[cloud,wind,rain]))
# False

So consider a simple model consisting of a one functional transform $T \in \mathcal{T}_{U,\mathrm{f},1}$ with underlying variables cloud and wind and a derived variable of cloud_and_wind with this relation -

cloud wind cloud and wind
none none none
none light light
none strong light
light none light
light light light
light strong light
heavy none strong
heavy light strong
heavy strong strong
cloud_and_wind = VarStr("cloud_and_wind")

def lltt(kk,ww,qq):
    return trans(unit(sset([llss(zip(kk + ww,ll)) for ll in qq])),sset(ww))


tt = lltt([cloud,wind],[cloud_and_wind],[
      [none, none, none],
      [none, light, light],
      [none, strong, light],
      [light, none, light],
      [light, light, light],
      [light, strong, light],
      [heavy, none, strong],
      [heavy, light, strong],
      [heavy, strong, strong]])

rpln(aall(ttaa(tt)))
# ({(cloud, heavy), (cloud_and_wind, strong), (wind, light)}, 1 % 1)
# ({(cloud, heavy), (cloud_and_wind, strong), (wind, none)}, 1 % 1)
# ({(cloud, heavy), (cloud_and_wind, strong), (wind, strong)}, 1 % 1)
# ({(cloud, light), (cloud_and_wind, light), (wind, light)}, 1 % 1)
# ({(cloud, light), (cloud_and_wind, light), (wind, none)}, 1 % 1)
# ({(cloud, light), (cloud_and_wind, light), (wind, strong)}, 1 % 1)
# ({(cloud, none), (cloud_and_wind, light), (wind, light)}, 1 % 1)
# ({(cloud, none), (cloud_and_wind, light), (wind, strong)}, 1 % 1)
# ({(cloud, none), (cloud_and_wind, none), (wind, none)}, 1 % 1)

rpln(ssplit([cloud,wind],ttaa(tt)))
# ({(cloud, heavy), (wind, light)}, {(cloud_and_wind, strong)})
# ({(cloud, heavy), (wind, none)}, {(cloud_and_wind, strong)})
# ({(cloud, heavy), (wind, strong)}, {(cloud_and_wind, strong)})
# ({(cloud, light), (wind, light)}, {(cloud_and_wind, light)})
# ({(cloud, light), (wind, none)}, {(cloud_and_wind, light)})
# ({(cloud, light), (wind, strong)}, {(cloud_and_wind, light)})
# ({(cloud, none), (wind, light)}, {(cloud_and_wind, light)})
# ({(cloud, none), (wind, none)}, {(cloud_and_wind, none)})
# ({(cloud, none), (wind, strong)}, {(cloud_and_wind, light)})

und(tt)
# {cloud, wind}

der(tt)
# {cloud_and_wind}

histogramsIsCausal(ttaa(tt))
# True

rpln(aall(tmul(aa,tt)))
# ({(cloud_and_wind, light)}, 12 % 1)
# ({(cloud_and_wind, none)}, 4 % 1)
# ({(cloud_and_wind, strong)}, 4 % 1)

Now we calculate the alignment between the derived variable, cloud_and_wind, and the rain,

algn(red(mul(aa,ttaa(tt)),[cloud_and_wind,rain]))
# 6.743705969634357

rpln(ssplit([cloud_and_wind],red(mul(aa,ttaa(tt)),[cloud_and_wind,rain])))
# ({(cloud_and_wind, light)}, {(rain, heavy)})
# ({(cloud_and_wind, light)}, {(rain, light)})
# ({(cloud_and_wind, light)}, {(rain, none)})
# ({(cloud_and_wind, none)}, {(rain, none)})
# ({(cloud_and_wind, strong)}, {(rain, heavy)})

So cloud_and_wind is more aligned with rain than any of cloud, wind or pressure.

Now consider a query which is ineffective in the sample, $Q \notin (A\%K)^{\mathrm{FS}}$, but is effective in the sample derived, $R \in (A * T)^{\mathrm{FS}}$ where $\{R\} = (\{Q\}^{\mathrm{U}} * T)^{\mathrm{FS}}$,

qq = hhaa(llhh([pressure,cloud,wind],[(1,[medium,heavy,light])]))

leq(qq,eff(red(aa,[pressure,cloud,wind])))
# False

rpln(aall(tmul(qq,tt)))
# ({(cloud_and_wind, strong)}, 1 % 1)

rr = hhaa(llhh([cloud_and_wind],[(1,[strong])]))

leq(rr,eff(tmul(aa,tt)))
# True

The forecast for rain is heavy,

def aarr(aa):
    return [(ss,float(q)) for (ss,q) in aall(aa)]

def query(qq,tt,aa,ll):
    return norm(red(mul(mul(tmul(qq,tt),ttaa(tt)),aa),ll))

rpln(aarr(query(qq,tt,aa,[rain])))
# ({(rain, heavy)}, 1.0)

We can calculate the resultant label histogram for all $3^3 = 27$ queries,

kk = sset([pressure,cloud,wind])

rpln([(ss, query(unit(sset([ss])),tt,aa,[rain])) for ss in cart(uu,kk)])
# ({(cloud, heavy), (pressure, high), (wind, light)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, high), (wind, none)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, high), (wind, strong)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, low), (wind, light)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, low), (wind, none)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, low), (wind, strong)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, medium), (wind, light)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, medium), (wind, none)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, heavy), (pressure, medium), (wind, strong)}, {({(rain, heavy)}, 1 % 1)})
# ({(cloud, light), (pressure, high), (wind, light)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, high), (wind, none)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, high), (wind, strong)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, low), (wind, light)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, low), (wind, none)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, low), (wind, strong)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, medium), (wind, light)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, medium), (wind, none)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, light), (pressure, medium), (wind, strong)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, none), (pressure, high), (wind, light)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, none), (pressure, high), (wind, none)}, {({(rain, none)}, 1 % 1)})
# ({(cloud, none), (pressure, high), (wind, strong)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, none), (pressure, low), (wind, light)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, none), (pressure, low), (wind, none)}, {({(rain, none)}, 1 % 1)})
# ({(cloud, none), (pressure, low), (wind, strong)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, none), (pressure, medium), (wind, light)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})
# ({(cloud, none), (pressure, medium), (wind, none)}, {({(rain, none)}, 1 % 1)})
# ({(cloud, none), (pressure, medium), (wind, strong)}, {({(rain, heavy)}, 1 % 6), ({(rain, light)}, 7 % 12), ({(rain, none)}, 1 % 4)})

For some queries the model is ambiguous. For example, when the pressure is low, but there is no cloud and winds are light, the forecast is usually for light rain, but not always,

qq2 = hhaa(llhh([pressure,cloud,wind],[(1,[low,none,light])]))
  
rpln(aarr(query(qq2,tt,aa,[rain])))
# ({(rain, heavy)}, 0.16666666666666666)
# ({(rain, light)}, 0.5833333333333334)
# ({(rain, none)}, 0.25)

The weather forecast example continues in Transform entropy.


top