Skip to content

PromotingMaskingRating

Zbyněk Šlajchrt edited this page Aug 1, 2015 · 42 revisions

15. Promoting, Masking and Rating Alternatives

So far we have been dealing with the promoting morphing strategy. Morpheus however offers other strategies, which employ other approaches to choosing the winning alternative. We are going to learn two new strategies in this lesson:

  • Masking strategy is used to reduce a morph model's list of alternatives by means of the so-called fragment mask
  • Rating strategy assigns a rating to one or more alternatives. Only those alternatives with the highest rating are used to select the winning alternative.

The rating strategy has the highest authority, then the masking one, while the least important is the promoting one.

Promoting

Before presenting the masking and rating strategies, we need to get more information on how the promoting strategy works.

Let us consider the following simple morph model

(Offline or Online) with (Raw or Pretty)

This model can be depicted as a tree shown in the following diagram.

Default promotion tree

The model has two dimensions that correspond to the two disjunctors (or) in the model. Each disjunctor contains two alternative fragments, thus the number of all alternatives defined by this model is 4. A very important aspect is the order of the alternatives in the list since the first alternative in the list is by default taken as the winner. According to the rules described here the list of the alternatives generated by the model will be sorted in the following way:

  1. {0, 2}
  2. {1, 2}
  3. {0, 3}
  4. {1, 3}

Definition: Two fragments are independent if they belong to two different disjunctors (i.e. dimensions).

The goal of the promoting strategy is to 'promote' one or more independent fragments. It means to transform the morph model tree in such a way that the promoted fragments are present in the first alternative in the list generated from the tree, i.e. the default winning alternative.

We will use the notation (contactCoord, printerCoord) to denote the fragments to be promoted. Then (0, 0) is the default promotion leading to choosing the {Offline, Raw} alternative.

In order to promote fragments (1, 0), the promoting strategy must transform the tree as follows.

Promotion tree 1

The new tree yields this list of alternatives.

  1. {1, 2}
  2. {0, 2}
  3. {1, 3}
  4. {0, 3}

We can continue by promoting (1, 1). The corresponding tree will then be this.

Promotion tree 2

And the corresponding list of alternative is:

  1. {1, 3}
  2. {0, 3}
  3. {1, 2}
  4. {0, 2}

And finally the remaining combination is (0, 1), which gives this tree:

Promotion tree 3

with these alternatives:

  1. {0, 3}
  2. {1, 3}
  3. {0, 2}
  4. {1, 2}
Masking

Masking allows us to suppress alternatives, which do not match the so-called fragment mask. The fragment mask specifies which fragments may be present in the winning alternative. By turning some fragments off we can effectively reduce the set of the alternatives. By default, all fragments are turned on.

In order to make the explanation clearer, let us introduce the following notation, which represents an alternative along with a bit vector indicating fragments contained in the alternative.

{fragments}[OfflineBit, OnlineBit, RawBit, PrettyBit]

The four alternatives from our model then look like this:

  1. {0, 2}[1, 0, 1, 0]
  2. {1, 2}[0, 1, 1, 0]
  3. {0, 3}[1, 0, 0, 1]
  4. {1, 3}[0, 1, 0, 1]

Now, the fragment mask for our model is a vector of four bits. A bit fN set to 1 indicates that the corresponding fragment may be present in the winning alternative.

mask = (f0 f1 f2 f3)

We can use this mask to reduce the original list of alternatives A by clearing some bits in the mask. The sublist S ⊂ A consists of all alternatives whose bit vector a masked with the fragment mask (bitwise AND) gives a. It can be formulated more precisely by the following formula.

∀ a ∈ S; a & mask = a

For a better manipulation with the fragment bits, let us construct the following matrix corresponding to the previous list of alternatives.

    |1 0 1 0|
    |0 1 1 0|
F = |1 0 0 1|
    |0 1 0 1|

When no fragment is explicitly specified, the mask is (1 1 1 1). Masking matrix F gives the same matrix. Thus there is no reduction of the original list of alternatives.

           |1 0 1 0|
           |0 1 1 0|
F & mask = |1 0 0 1| 
           |0 1 0 1|

If we wish to constrain the list of alternatives only to those not containing the Pretty fragment, the mask will be (1 1 1 0). Masking matrix F then will yield the following matrix.

           |1 0 1 0|
           |0 1 1 0|
F & mask = |1 0 0 0| 
           |0 1 0 0|

Here, only the first two rows remain same after the mask is applied. The first alternative in the sublist, which preserves the order of the original list, is the winner.

  1. {0, 2}[1, 0, 1, 0]
  2. {1, 2}[0, 1, 1, 0]

If we clear an additional fragment to the mask, let us say Online, the mask will be (1 0 1 0). Then the masked matrix F will be

           |1 0 1 0|
           |0 0 1 0|
F & mask = |1 0 0 0| 
           |0 0 0 0|

where only the first row remains unchanged. This single alternative becomes the winner.

  1. {0, 2}[1, 0, 1, 0]

Rating

The rating strategy allows us to rate individual alternatives. Then the winner alternative is selected only from those alternatives having the highest rating. For a better understanding let us use the following notation, which depicts the rating of an alternative.

{fragments}:Rating

By default the alternatives have no rating, i.e. their rating is 0. The four alternatives from our model then look like this:

  1. {0, 2}:0
  2. {1, 2}:0
  3. {0, 3}:0
  4. {1, 3}:0

We can explicitly assign new ratings to a selected sub-set of the original alternatives. Let's say we will rate alternatives 1 and 4 with rating 1. Then the sub-list will look like this

  1. {0, 2}:1
  2. {1, 3}:1

since only these two alternatives have the highest rating. The winner is the first alternative in this sub-list.

Composing strategies

All strategies can be composed in any order. In the following example we will see the effect of all strategies on the choosing of the winning alternative. We will use the following text decorations to depict the winner, underlining a mask-matching alternative and striking-out a suppressed alternative with a low rating.

The default list of alternatives is this:

  1. {0, 2}:0
  2. {1, 2}:0
  3. {0, 3}:0
  4. {1, 3}:0

Let us first promote the fragment 1.

  1. {1, 2}:0
  2. {0, 2}:0
  3. {1, 3}:0
  4. {0, 3}:0

Then we will unmask (clear) fragment 2.

  1. {1, 2}:0
  2. {0, 2}:0
  3. {1, 3}:0
  4. {0, 3}:0

And next we will rate alternatives {1, 2} and {0, 3} by 1.

  1. {1, 2}:1
  2. {0, 2}:0
  3. {1, 3}:0
  4. {0, 3}:1

And finally we will mask (turn on) fragment 2 again and unmask fragment 3 (clear).

  1. {1, 2}:1
  2. {0, 2}:0
  3. {1, 3}:0
  4. {0, 3}:1

A Use Case

The following use-case shows how the three strategies can be composed in a real code.

Let us first create a morph kernel in two steps. First we have to create the model.

val contactModel = parse[(OfflineContact or OnlineContact) with
   (ContactRawPrinter or ContactPrettyPrinter) with
   (StandardOutputChannel or MemoryOutputChannel)](true)

Then we construct a stack of three promoting strategies, each controlling one dimension. We do not employ the other two strategies yet. Notice the LastRatingStrategy strategy used as the root (bottom) strategy. It is actually a strategy returning the alternatives (i.e. the list of alternatives, the tree, the fragment mask and the ratings) of the morph, on which method remorph is being called. When calling remorph repeatedly, it always uses the output alternatives from the last invocation as the input alternatives in the next invocation.

var channelCoord: Int = 0
val channelStr = promote[StandardOutputChannel or MemoryOutputChannel](new LastRatingStrategy[contactModel.Model](), channelCoord)
var printerCoord: Int = 0
val printerStr = promote[ContactRawPrinter or ContactPrettyPrinter](channelStr, printerCoord)
var statusCoord: Int = 0
val contactStr = promote[OfflineContact or OnlineContact](printerStr, statusCoord)

Now we can instantiate the kernel.

val contactData = ContactData("Pepa", "Novák", male = true, email="[email protected]", Locale.CANADA)
implicit val offlineContactFrag = single[OfflineContact, Contact](contactData)
implicit val onlineContactFrag = single[OnlineContact, Contact](contactData)
val contactKernel = singleton(contactModel, contactStr)

In order to see the list of the structure of individual winner alternatives, we will prepare this helper method printing alternatives from the whole combinatorial space (2x2x2).

def printAllAlts(): Unit = {
   for (i <- 0 to 1; j <- 0 to 1; k <- 0 to 1) {
      channelCoord = i
      printerCoord = j
      statusCoord = k
      contactKernel.~.remorph
      println(contactKernel.~.myAlternative)
   }
}

Printing the list of alternatives yields this output.

(OfflineContact, ContactRawPrinter, StandardOutputChannel)
(OnlineContact, ContactRawPrinter, StandardOutputChannel)
(OfflineContact, ContactPrettyPrinter, StandardOutputChannel)
(OnlineContact, ContactPrettyPrinter, StandardOutputChannel)
(OfflineContact, ContactRawPrinter, MemoryOutputChannel)
(OnlineContact, ContactRawPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)

Now we are going to employ the masking strategy, which will suppress all alternative containing StandardOutputChannel.

var banStdOut = 1
val maskStrategy = unmask[\?[StandardOutputChannel]](contactStr, banStdOut)
contactKernel.~.remorph(maskStrategy)
printAllAlts()

Remember that \?[StandardOutputChannel] is equivalent to Unit or StandardOutputChannel. Setting banStdOut to 0 will select {Unit} or {} empty alternative, thus no fragment gets unmasked. On the contrary, the fragment in the other (not selected) alternative {StandardOutputChannel} is turned on, i.e. it does not change its status, since by default all fragments are on. Since no fragment was cleared, all alternatives are allowed.

On the other hand, when banStdOut is set to 1 then the fragment in the {StandardOutputChannel} alternative is unmasked (cleared). In such a case the only allowed alternatives are those not containing the StandardOutputChannel fragment.

Printing all combinations proves that despite promoting alternatives with StandardOutputChannel too, they are overridden by the alternatives not containing StandardOutputChannel.

(OfflineContact, ContactRawPrinter, MemoryOutputChannel)
(OnlineContact, ContactRawPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OfflineContact, ContactRawPrinter, MemoryOutputChannel)
(OnlineContact, ContactRawPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)

Next, we will employ the rating strategy, which assigns rating 1 to the alternatives containing ContactPrettyPrinter.

var fixPretty = Set((0, 1))
val ratingStrategy = rate[ContactPrettyPrinter](contactKernel.~.strategy, fixPretty)
contactKernel.~.remorph(ratingStrategy)
printAllAlts()

The rate macro has similar signature as promote and mask, however the last argument contains a function returning a set of pairs, where each pair consists of the number of the alternative in the sub-model specified in the type arguments, and the rating.

The result of the printing of the whole space will be homogenous now.

(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)

And now we are going to unapply the effect of the new strategies. First, let us unapply the fragment mask by

banStdOut = 0
contactKernel.~.remorph
printAllAlts()

Setting the banStdOut to 0 turns StandardOutputChannel fragment making all fragments allowed. Then the strategy promoting StandardOutputChannel and the strategy rating higher the ContactPrettyPrinter prevail:

(OfflineContact, ContactPrettyPrinter, StandardOutputChannel)
(OnlineContact, ContactPrettyPrinter, StandardOutputChannel)
(OfflineContact, ContactPrettyPrinter, StandardOutputChannel)
(OnlineContact, ContactPrettyPrinter, StandardOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)

And finally, we will unapply the rating strategy by rating the alternatives with ContactPrettyPrinter by 0.

fixPretty = Set((0, 0))
contactKernel.~.remorph
printAllAlts()
(OfflineContact, ContactRawPrinter, StandardOutputChannel)
(OnlineContact, ContactRawPrinter, StandardOutputChannel)
(OfflineContact, ContactPrettyPrinter, StandardOutputChannel)
(OnlineContact, ContactPrettyPrinter, StandardOutputChannel)
(OfflineContact, ContactRawPrinter, MemoryOutputChannel)
(OnlineContact, ContactRawPrinter, MemoryOutputChannel)
(OfflineContact, ContactPrettyPrinter, MemoryOutputChannel)
(OnlineContact, ContactPrettyPrinter, MemoryOutputChannel)