15.3.6 Products of Domains

We can now define products of domains. The elements of product domains are vectors (n-tuples) of elements of other domains. From the operational view, we have to provide converter functions that map vectors in D_0\times \ldots \times D_n to integer indexes and vice versa.

<Product of Domains>=
fun{Product Domains}  %% list(domain) -> domain
      DomTable = {List.toTuple unit Domains}
      N = {Length Domains}
      Size = {Prod 1 N fun{$ I}
                          DomTable.I.size
                       end}
 
      %% forth conversion
      
<ToIndex> 
      
      %% back conversion
      
<ToVector> 
   in 
      unit(toIndex  :ToIndex
           toElement:ToVector
           size     :Size)
   end  

For simplicity, let us assume first that the elements of the given domains D_0,\ \ldots\ , D_n are already integer indexes:

\begin{array}{rcl}
    D_0 &=& \{0,\ldots,m_0\} \\
        & &  \ldots \\
    D_n &=& \{0,\ldots,m_n\} \\
\end{array}

We can then describe the index of a vector (d_0,\ldots,d_n) \in D_0\times\ldots\times D_n by the following formula.

  \mbox{index}((d_0,\ldots,d_n) = \sum_{i=0}^{n}  d_i * \prod_{j=0}^{i-1} m_j + 1

This formula is well known for the case where all domains contain the digits \{0,\ldots,9\}, i.e. if m_1=\ldots m_n = 9. In this case, the formula tells us how to read a sequence of digits as a decimal number (up to inversion).

   \mbox{index}((d_n,\ldots,d_0)) = \sum_{i=0}^{n}  d_i * 10^i

For implementing the conversion from vectors to numbers, we use an Oz table DomTable to index the domains D_0,\ \ldots\ , D_n by integers 1,\ \ldots\ ,n+1. Note that we exploit the conversion functions of the factors of the product to define the conversion functions of the product itself.

<ToIndex>=
fun{ToIndex Vector}  %% list(feature) -> int
         if {Length Vector} \= N
         then raise unit(msg:'length of vector not valid' 
                         function:'ToIndex' 
                         file:'domain.oz' 
                         vector:Vector
                         length:N)
              end   
         end  
         VectorTable = {List.toTuple unit Vector}
      in   
         {Sum 1 N fun{$ I}
                     {DomTable.I.toIndex VectorTable.I} *   
                     {Prod 1 I-fun{$ J}
                                    DomTable.J.size
                                 end}
                  end}  
      end

The back translation from indexes to vectors of elements requires some division modulo operations, which require some care.

<ToVector>=
fun{ToVectorHelp Index N InVector}
         if N==0
         then InVector
         else   
            Size={Prod 1 N-fun{$ I} DomTable.I.size end}
            NextVector = {DomTable.N.toElement (Index div Size)} | InVector
         in   
            {ToVectorHelp (Index mod Size) N-1 NextVector}
         end   
      end   
      fun{ToVector Index}  %% int -> list(feature)
         if Index < 0 orelse Index > Size-1
         then 
            raise error(function:'ToVector' 
                        file:'domain.oz' 
                        msg:'index out of range' 
                        index:Index
                        range:0#(Size-1))
            end   
         end   
         {ToVectorHelp Index N nil}
      end  


Denys Duchier, Claire Gardent and Joachim Niehren
Version 1.3.99 (20050412)