Skip to content

PromotingMaskingRating

Zbyněk Šlajchrt edited this page Jun 16, 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 must be present in the winning alternative. It effectively reduces the set of the alternatives.

In order to make the explanation easier, 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 must be present.

mask = (f0 f1 f2 f3)

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

∀ a ∈ S; a & mask = mask

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 (0 0 0 0). Masking matrix F gives the zero matrix, where all raws matches the mask. Thus there is no reduction of the original list of alternatives.

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

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

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

Here, only the last two rows match the mask. The first alternative in the sublist, which preserves the order of the original list, is the winner.

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

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

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

where only the last row matches the mask. This single alternative becomes the winner.

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

Note: Using an invalid mask is equivalent to that of the empty mask, i.e. no alternative is suppressed.

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 rating to a selected sub-set of the original alternatives. Let's say we will rate alternatives 1 and 4 by 1. Then the sub-list will look like this

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

since only this 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 winner alternative. We will use the following text decorations to depict the winner alternative, a mask-matching alternative and 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 mask fragment 3.

  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 unmask fragment 3 and mask fragment 2.

  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 not containing MemoryOutputChannel.

var fixMemOut = 1
val maskStrategy = mask[\?[MemoryOutputChannel]](contactStr, fixMemOut)
contactKernel.~.remorph(maskStrategy)
printAllAlts()

Remember that \?[MemoryOutputChannel is equivalent to Unit or MemoryOutputChannel. Setting fixMem to 0 will select {Unit} or {} alternative, which maps to all alternatives in the source model and thus all fragments from all source alternatives are masked. If fixMem is set to 1 then the {MemoryOutputChannel} alternative is selected, which is mapped to four source alternatives containing the {MemoryOutputChannel} fragment. Thus only the fragments from these four alternatives are projected into the fragment mask.

Printing all combinations proves that despite promoting alternatives with StandardOutputChannel too, they are overridden by the fragment mask having the MemoryOutputChannel bit set.

(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

fixMemOut = 0
contactKernel.~.remorph
printAllAlts()

Setting the fixMemOut to 0 selects all fragments in the fragment mask, thus all fragments are equal.

(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)