def construction_3_3(k,n,m,i): r""" Return an `OA(k,nm+i)`. This is Wilson's construction with `i` truncated columns of size 1 and such that a block `B_0` of the incomplete OA intersects all truncated columns. As a consequence, all other blocks intersect only `0` or `1` of the last `i` columns. This allow to consider the block `B_0` only up to its first `k` coordinates and then use a `OA(k,i)` instead of a `OA(k,m+i) - i.OA(k,1)`. This is construction 3.3 from [AC07]_. INPUT: - ``k,n,m,i`` (integers) such that the following designs are available : `OA(k,n),OA(k,m),OA(k,m+1),OA(k,r)`. .. SEEALSO:: :func:`find_construction_3_3` EXAMPLES:: sage: from sage.combinat.designs.orthogonal_arrays_recursive import find_construction_3_3 sage: from sage.combinat.designs.orthogonal_arrays_recursive import construction_3_3 sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array sage: k=11;n=177 sage: is_orthogonal_array(construction_3_3(*find_construction_3_3(k,n)[1]),k,n,2) True """ from orthogonal_arrays import wilson_construction, OA_relabel, incomplete_orthogonal_array # Builds an OA(k+i,n) containing a block [0]*(k+i) OA = incomplete_orthogonal_array(k+i,n,(1,)) OA = [[(x+1)%n for x in B] for B in OA] # Truncated version OA = [B[:k]+[0 if x == 0 else None for x in B[k:]] for B in OA] OA = wilson_construction(OA,k,n,m,i,[1]*i,check=False)[:-i] matrix = [range(m)+range(n*m,n*m+i)]*k OA.extend(OA_relabel(orthogonal_array(k,m+i),k,m+i,matrix=matrix)) assert is_orthogonal_array(OA,k,n*m+i) return OA
def construction_q_x(k,q,x,check=True): r""" Return an `OA(k,(q-1)*(q-x)+x+2)` using the `q-x` construction. Let `v=(q-1)*(q-x)+x+2`. If there exists a projective plane of order `q` (e.g. when `q` is a prime power) and `0<x<q` then there exists a `(v-1,\{q-x-1,q-x+1\})`-GDD of type `(q-1)^{q-x}(x+1)^1` (see [Greig99]_ or Theorem 2.50, section IV.2.3 of [DesignHandbook]_). By adding to the ground set one point contained in all groups of the GDD, one obtains a `(v,\{q-x-1,q-x+1,q,x+2\})`-PBD with exactly one set of size `x+2`. Thus, assuming that we have the following: - `OA(k,q-x-1)-(q-x-1).OA(k,1)` - `OA(k,q-x+1)-(q-x+1).OA(k,1)` - `OA(k,q)-q.OA(k,1)` - `OA(k,x+2)` Then we can build from the PBD an `OA(k,v)`. Construction of the PBD (shared by Julian R. Abel): Start with a resolvable `(q^2,q,1)`-BIBD and put the points into a `q\times q` array so that rows form a parallel class and columns form another. Now delete: - All `x(q-1)` points from the first `x` columns and not in the first row - All `q-x` points in the last `q-x` columns AND the first row. Then add a point `p_1` to the blocks that are rows. Add a second point `p_2` to the `q-x` blocks that are columns of size `q-1`, plus the first row of size `x+1`. INPUT: - ``k,q,x`` -- integers such that `0<x<q` and such that Sage can build: - A projective plane of order `q` - `OA(k,q-x-1)-(q-x-1).OA(k,1)` - `OA(k,q-x+1)-(q-x+1).OA(k,1)` - `OA(k,q)-q.OA(k,1)` - `OA(k,x+2)` - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. .. SEEALSO:: - :func:`find_q_x` - :func:`~sage.combinat.designs.block_design.projective_plane` - :func:`~sage.combinat.designs.orthogonal_arrays.orthogonal_array` - :func:`~sage.combinat.designs.orthogonal_arrays.OA_from_PBD` EXAMPLES:: sage: from sage.combinat.designs.orthogonal_arrays_recursive import construction_q_x sage: _ = construction_q_x(9,16,6) REFERENCES: .. [Greig99] Designs from projective planes and PBD bases Malcolm Greig Journal of Combinatorial Designs vol. 7, num. 5, pp. 341--374 1999 """ from sage.combinat.designs.orthogonal_arrays import OA_from_PBD from sage.combinat.designs.orthogonal_arrays import incomplete_orthogonal_array n = (q-1)*(q-x)+x+2 # We obtain the qxq matrix from a OA(q,q)-q.OA(1,q). We will need to add # blocks corresponding to the rows/columns OA = incomplete_orthogonal_array(q,q,(1,)*q) TD = [[i*q+xx for i,xx in enumerate(B)] for B in OA] # Add rows, extended with p1 and p2 p1 = q**2 p2 = p1+1 TD.extend([[ii*q+i for ii in range(q)]+[p1] for i in range(1,q)]) TD.append( [ii*q for ii in range(q)]+[p1,p2]) # Add Columns. We do not add some columns which would have size 1 after we # delete points. # # TD.extend([range(i*q,(i+1)*q) for i in range(x)]) TD.extend([range(i*q,(i+1)*q)+[p2] for i in range(x,q)]) points_to_delete = set([i*q+j for i in range(x) for j in range(1,q)]+[i*q for i in range(x,q)]) points_to_keep = set(range(q**2+2))-points_to_delete relabel = {i:j for j,i in enumerate(points_to_keep)} # PBD is a (n,[q,q-x-1,q-x+1,x+2])-PBD PBD = [[relabel[xx] for xx in B if not xx in points_to_delete] for B in TD] # Taking the unique block of size x+2 assert map(len,PBD).count(x+2)==1 for B in PBD: if len(B) == x+2: break # We call OA_from_PBD without the block of size x+2 as there may not exist a # OA(k,x+2)-(x+2).OA(k,1) PBD.remove(B) OA = OA_from_PBD(k,(q-1)*(q-x)+x+2,PBD,check=False) # Filling the hole for xx in B: OA.remove([xx]*k) for BB in orthogonal_array(k,x+2): OA.append([B[x] for x in BB]) if check: assert is_orthogonal_array(OA,k,n,2) return OA