The CLP Procedure

Example 2.13 Balanced Incomplete Block Design

(View the complete code for this example.)

Balanced incomplete block design (BIBD) generation is a standard combinatorial problem from design theory. The concept was originally developed in the design of statistical experiments; applications have expanded to other fields, such as coding theory, network reliability, and cryptography. A BIBD is an arrangement of v distinct objects into b blocks such that the following conditions are met:

  • Each block contains exactly k distinct objects.

  • Each object occurs in exactly r different blocks.

  • Every two distinct objects occur together in exactly lamda blocks.

A BIBD is therefore specified by its parameters left-parenthesis v comma b comma r comma k comma lamda right-parenthesis. It can be proved that when a BIBD exists, its parameters must satisfy the following conditions:

  • r v equals b k

  • lamda left-parenthesis v minus 1 right-parenthesis equals r left-parenthesis k minus 1 right-parenthesis

  • b greater-than-or-equal-to v

The preceding conditions are not sufficient to guarantee the existence of a BIBD (Prestwich 2001). For example, the parameters left-parenthesis 15 comma 21 comma 7 comma 5 comma 2 right-parenthesis satisfy the preceding conditions, but a BIBD that has these parameters does not exist. Computational methods of BIBD generation usually suffer from combinatorial explosion, in part because of the large number of symmetries: for any solution, any two objects or blocks can be exchanged to obtain another solution.

This example demonstrates how to express a BIBD problem as a CSP and how to use lexicographic ordering constraints to break symmetries. (Note that this example is for illustration only. SAS provides an autocall macro, MKTBIBD, for solving BIBD problems.) The most direct CSP model for BIBD, as described in Meseguer and Torras (2001), represents a BIBD as a v times b matrix X. Each matrix entry is a Boolean decision variable upper X Subscript i comma c that satisfies upper X Subscript i comma c Baseline equals 1 if and only if block c contains object i. The condition that each object occurs in exactly r blocks (or, equivalently, that there are r 1s per row) can be expressed as v linear constraints:

sigma-summation Underscript c equals 1 Overscript b Endscripts upper X Subscript i comma c Baseline equals r normal f normal o normal r i equals 1 comma ellipsis comma v

Alternatively, you can use global cardinality constraints to ensure that there are exactly b minus r 0s and r 1s in upper X Subscript i comma 1,…, upper X Subscript i comma b for each object i:

normal g normal c normal c left-parenthesis upper X Subscript i comma 1 Baseline comma ellipsis comma upper X Subscript i comma b Baseline right-parenthesis equals left-parenthesis left-parenthesis 0 comma 0 comma b minus r right-parenthesis left-parenthesis 1 comma 0 comma r right-parenthesis right-parenthesis normal f normal o normal r i equals 1 comma ellipsis comma v

Similarly, the condition that each block contains exactly k objects (there are k 1s per column) can be specified by the following constraints:

normal g normal c normal c left-parenthesis upper X Subscript 1 comma c Baseline comma ellipsis comma upper X Subscript v comma c Baseline right-parenthesis equals left-parenthesis left-parenthesis 0 comma 0 comma v minus k right-parenthesis left-parenthesis 1 comma 0 comma k right-parenthesis right-parenthesis normal f normal o normal r c equals 1 comma ellipsis comma b

To enforce the final condition that every two distinct objects occur together in exactly lamda blocks (equivalently, that the scalar product of every pair of rows equal lamda), you can introduce the auxiliary variables upper P Subscript i comma j comma c for every i less-than j, which indicate whether objects i and j both occur in block c. The following reified constraint ensures that upper P Subscript i comma j comma c Baseline equals 1 if and only if block c contains both objects i and j:

normal r normal e normal i normal f normal y upper P Subscript i comma j comma c Baseline colon left-parenthesis upper X Subscript i comma c Baseline plus upper X Subscript j comma c Baseline equals 2 right-parenthesis

The following constraints ensure that the final condition holds:

normal g normal c normal c left-parenthesis upper P Subscript i comma j comma 1 Baseline comma ellipsis comma upper P Subscript i comma j comma b Baseline right-parenthesis equals left-parenthesis left-parenthesis 0 comma 0 comma b minus lamda right-parenthesis left-parenthesis 1 comma 0 comma lamda right-parenthesis right-parenthesis normal f normal o normal r i equals 1 comma ellipsis comma v minus 1 normal a normal n normal d j equals i plus 1 comma ellipsis comma v

The objects and the blocks are interchangeable, so the matrix X has total row symmetry and total column symmetry. Because of the constraints on the rows, no pair of rows can be equal unless r equals lamda. To break the row symmetry, you can impose strict lexicographical ordering on the rows of X as follows:

left-parenthesis upper X Subscript i comma 1 Baseline comma ellipsis comma upper X Subscript i comma b Baseline right-parenthesis less-than Subscript normal l normal e normal x Baseline left-parenthesis upper X Subscript i minus 1 comma 1 Baseline comma ellipsis comma upper X Subscript i minus 1 comma b Baseline right-parenthesis normal f normal o normal r i equals 2 comma ellipsis comma v

To break the column symmetry, you can impose lexicographical ordering on the columns of X as follows:

left-parenthesis upper X Subscript 1 comma c Baseline comma ellipsis comma upper X Subscript v comma c Baseline right-parenthesis less-than-or-equal-to Subscript normal l normal e normal x Baseline left-parenthesis upper X Subscript 1 comma c minus 1 Baseline comma ellipsis comma upper X Subscript v comma c minus 1 Baseline right-parenthesis normal f normal o normal r c equals 2 comma ellipsis comma b

The following SAS macro incorporates all the preceding constraints. For the specified parameters left-parenthesis v comma b comma r comma k comma lamda right-parenthesis, the macro either finds BIBDs or proves that a BIBD does not exist.

%macro bibd(v, b, r, k, lambda, out=bibdout);
   /* Arrange v objects into b blocks such that:
         (i) each object occurs in exactly r blocks,
         (ii) each block contains exactly k objects,
         (iii) every pair of objects occur together in exactly lambda blocks.

      Equivalently, create a binary matrix with v rows and b columns,
      with r 1s per row, k 1s per column,
      and scalar product lambda between any pair of distinct rows.
   */

   /* Check necessary conditions */
   %if (%eval(&r * &v) ne %eval(&b * &k)) or
      (%eval(&lambda * (&v - 1)) ne %eval(&r * (&k - 1))) or
      (&v > &b) %then %do;
      %put BIBD necessary conditions are not met.;
      %goto EXIT;
   %end;

   proc clp out=&out(keep=x:) domain=[0,1] varselect=FIFO;
      /* Decision variables: */
      /* Decision variable Xi_c = 1 iff object i occurs in block c. */
      var (
           %do i=1 %to &v;
              x&i._1-x&i._&b.
           %end;
          ) = [0,1];

      /* Mandatory constraints: */
      /* (i) Each object occurs in exactly r blocks. */
      %let q = %eval(&b.-&r.);  /* each row has &q 0s and &r 1s */
      %do i=1 %to &v;
         gcc( x&i._1-x&i._&b. ) = ((0,0,&q.) (1,0,&r.));
      %end;

      /* (ii) Each block contains exactly k objects. */
      %let h = %eval(&v.-&k.);  /* each column has &h 0s and &k 1s */
      %do c=1 %to &b;
         gcc(
             %do i=1 %to &v;
                x&i._&c.
             %end;
            ) = ((0,0,&h.) (1,0,&k.));
      %end;

      /* (iii) Every pair of objects occurs in exactly lambda blocks. */
      %let t = %eval(&b.-&lambda.);
      %do i=1 %to %eval(&v.-1);
         %do j=%eval(&i.+1) %to &v;
            /* auxiliary variable p_i_j_c =1 iff both i and j occur in c */
            var ( p&i._&j._1-p&i._&j._&b. ) = [0,1];
            %do c=1 %to &b;
               reify p&i._&j._&c.: (x&i._&c. + x&j._&c. = 2);
            %end;

            gcc(p&i._&j._1-p&i._&j._&b.) = ((0,0,&t.) (1,0,&lambda.));
         %end;
      %end;

      /* Symmetry breaking constraints: */
      /* Break row symmetry via lexicographic ordering constraints. */
      %do i = 2 %to &v.;
         %let i1 = %eval(&i.-1);
         lexico( (x&i._1-x&i._&b.) LEX_LT (x&i1._1-x&i1._&b.) );
      %end;

      /* Break column symmetry via lexicographic ordering constraints. */
      %do c = 2 %to &b.;
         %let c1 = %eval(&c.-1);
         lexico( ( %do i = 1 %to &v.;
                      x&i._&c.
                   %end; )
                 LEX_LE
                 ( %do i = 1 %to &v.;
                      x&i._&c1.
                   %end; ) );
      %end;
   run;
   %put &_orclp_;
%EXIT:
%mend bibd;

The following statement invokes the macro to find a BIBD design for the parameters left-parenthesis 15 comma 15 comma 7 comma 7 comma 3 right-parenthesis:


%bibd(15,15,7,7,3);

The output is displayed in Output 2.13.1.

Output 2.13.1: Balanced Incomplete Block Design for (15,15,7,7,3)

Balanced Incomplete Block Design Problem
(15, 15, 7, 7, 3)

ObsBlock1Block2Block3Block4Block5Block6Block7Block8Block9Block10Block11Block12Block13Block14Block15
1111111100000000
2111000011110000
3110100010001110
4101010001001101
5100101000111001
6100010100110110
7100001111000011
8011000100101011
9010100101010101
10010011010100101
11010011001011010
12001110010010011
13001101001100110
14001001110011100
15000110111101000


Last updated: September 16, 2021