cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c Program to construct Golomb rulers from projective planes
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c IBM SOFTWARE DISCLAIMER
c
c conpp.f (version 1.1)
c Copyright (1998,1986)
c International Business Machines Corporation
c
c Permission to use, copy, modify and distribute this software for
c any purpose and without fee is hereby granted, provided that this
c copyright and permission notice appear on all copies of the software.
c The name of the IBM corporation may not be used in any advertising or
c publicity pertaining to the use of the software. IBM makes no
c warranty or representations about the suitability of the software
c for any purpose. It is provided "AS IS" without any express or
c implied warranty, including the implied warranties of merchantability,
c fitness for a particular purpose and non-infringement. IBM shall not
c be liable for any direct, indirect, special or consequential damages
c resulting from the loss of use, data or projects, whether in action
c of contract or tort, arising out or in the connection with the use or
c performance of this software.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c Author: James B. Shearer
c email: jbs@watson.ibm.com
c website: http://www.research.ibm.com/people/s/shearer/
c date: 1998 (based on code written in 1986)
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c Version 1.1 (12/11/98) - Renamed variables to conform with
c exhaustive search routines.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c Requires: ESSL library or portable versions of ESSL routines
c durand, isort (see essl.f)
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c This program constructs good but not necessarily optimal
c Golomb rulers from finte projective planes.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c Theory
c
c Suppose p is a prime power. Consider the Galois field GF(p) and
c the extension field GF(p**3). Let x be a generator of the cyclic
c multiplicative group of GF(p**3). Then the elements GF(p**3) can
c be represented in the form a+b*x+c*x**2 where a,b,c are elements of
c GF(p). (Note in particular x**3 can be so written, so we may take
c x to be the root of a cubic polynomial over GF(p).) Let two non-
c zero elements, {y,z}, of GF(p**3) be equivalent if one is a scalar
c of the other (ie y/z is an element of the base field GF(p)). This
c partitions the p**3-1 nonzero elements of GF(p**3) into p**2+p+1
c classes (of size p-1). As is well known these classes can be
c thought of as the points of a finite projective plane. Consider
c such a point consisting of the class {y1, y2 ...}. Let y1=x**n1,
c y2=x**n2 ... . We claim n1=n2 mod (p**2+p+1). (Because the
c elements of the base field are generated by x**(p**2+p+1).) Hence
c it is easy to see that we can associate each point of the plane
c with an unique residue mod p**2+p+1. Consider the residues
c associated with the p+1 points on a line in the projective plane.
c We claim these p+1 residues form a distinct difference set mod
c p**2+p+1. Consider for example the points (a+b*x+c*x**2) with
c third coordinate (c) zero. There are p+1 such points which we
c can take to be a+x (a in GF(p)) and 1. Suppose the associated
c residues are not a modular distinct difference set. Then we
c would have for example (a+x)/(b+x)=e*(c+x)/(d+x) (a,b,c,d,e in
c GF(p)). But then x**2+(a+d)*x+a*d=e*(x**2+(b+c)*x+b*c). Or
c equating powers of x, e=1, a+d=b+c, a*d=b*c. So {a,d}={b,c}
c (since they are roots of the same quadratic polynomial). The
c claim follows by contradiction. The other cases involving the
c point 1 are similar.
c Modular distinct difference sets can be unwound and truncated
c to form Golomb rulers. Note we may multiply a modular distinct
c difference set by anything prime to the modulus to obtain another
c modular distinct difference set. The program below tests all
c possibilities to obtain the shortest Golomb rulers.
c The modular difference set construction is due to Singer [2],
c the application to Golomb rulers to Robinson and Bernstein [1].
c The program below finds the best Golomb rulers using this
c construction for prime powers up to maxn-1. It will start to
c fail as maxn**4 overflows integer*4 arithmetic (loop 230). A
c program which just handled primes and not prime powers would be
c simpler.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c References
c
c 1. J. P. Robinson and A. J. Bernstein, "A class of binary recurrent
c codes with limited error propagation", IEEE Transactions on
c Information Theory, IT-13(1967), p. 106-113.
c 2. J. Singer, "A theorem in finite projective geometry and some
c applications to number theory", Transactions American
c Mathematical Society, 43(1938), p.377-385.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
Parameter (maxn=160,maxpow=10)
integer*4 len(maxn),nval(maxn),mrec(maxn,maxn)
integer*4 ids(maxn)
integer*4 mw(2*maxn)
integer*4 ipc(3*maxpow),iit(3*maxpow),itemp(3*maxpow)
real*8 buf(3*maxpow)
integer*4 ibase(3*maxpow,2*maxpow),iperp(3*maxpow,maxpow)
integer*4 irep(maxn),ipiv(maxn)
integer*8 array_len, array_size
integer(4), external :: cmp_function
* .. External Subroutines ..
EXTERNAL DLARNV
* .. Local Arrays ..
INTEGER ISEED( 4 )
*
* Initialize seed for random number generator DLARNV.
*
DO 11 I = 1, 4
ISEED( I ) = 1
11 CONTINUE
c initialize best rulers so far
do 5 j=2,maxn
len(j)=maxn*maxn
nval(j)=0
5 continue
c loop over n
do 10 n=2,maxn-1
c check if n is a prime power
c first find smallest prime divisor
do 20 j=2,n
if(mod(n,j).eq.0)go to 30
20 continue
stop "error 20"
30 np=j
npow=1
nprod=j
c next check if n is a power of the smallest prime divisor
40 if(nprod.eq.n)go to 50
nprod=nprod*np
npow=npow+1
if(nprod.le.n)go to 40
c n is not a prime power, go to next n
go to 10
c n is a prime power, construct GF(n**3)=GF(np**ndeg)
50 ndeg=3*npow
c generate random coefficients for monic polynomial P,
c with degree ndeg over GF(np)
60 call irand(ipc,np,ndeg,buf,iseed)
c check if constant term is 0, if so generate another polynomial
if(ipc(1).eq.0)go to 60
c check if x is a multiplicative generator mod P
c initialize iit (x**0) to the unit vector
do 70 j=1,ndeg
iit(j)=0
70 continue
iit(1)=1
c generate powers of x
do 80 j=1,n*n*n-2
c multiply iit by x
itemp(1)=ipc(1)*iit(ndeg)
do 90 i=2,ndeg
itemp(i)=iit(i-1)+ipc(i)*iit(ndeg)
90 continue
do 100 i=1,ndeg
iit(i)=mod(itemp(i),np)
100 continue
c check if power of x is 1 prematurely
if(iit(1).ne.1)go to 80
do 110 i=2,ndeg
if(iit(i).ne.0)go to 80
110 continue
c this polynomial no good, go generate another
go to 60
80 continue
c All powers of x ok. We now have a representation of GF(n**3) as
c arithmetic mod a polynomial over GF(np)
c The field GF(n**3) is an extension of the field GF(n). We need
c a way of identifying elements of the subspace generated by GF(n)
c and x. This is easy when n is a prime rather than a prime power,
c these are the elements with x**2 term 0. The prime power case is
c more complicated, we find a linear basis for the space and then
c for the perpendicular space. We can then test by looking at
c inner products with the basis of the perpendicular space.
c First npow powers of x**(n**2+n+1) span GF(n)
c Set first element of GF(n) basis to 1
do 85 j=1,ndeg
ibase(j,1)=0
85 continue
ibase(1,1)=1
c find remaining elements of basis
ibp=n**2+n+1
c initialize iit (x**0) to the unit vector
do 120 j=1,ndeg
iit(j)=0
120 continue
iit(1)=1
c generate powers of x
do 125 ja=2,npow
do 130 j=1,ibp
c multiply iit by x
itemp(1)=ipc(1)*iit(ndeg)
do 140 i=2,ndeg
itemp(i)=iit(i-1)+ipc(i)*iit(ndeg)
140 continue
do 150 i=1,ndeg
iit(i)=mod(itemp(i),np)
150 continue
130 continue
c add to basis vectors
do 160 j=1,ndeg
ibase(j,ja)=iit(j)
160 continue
125 continue
c now find basis of space generated by GF(n) and x.
c generate n additional basis vectors by multiplying first n vectors by x
do 170 ja=1,npow
itemp(1)=ipc(1)*ibase(ndeg,ja)
do 180 i=2,ndeg
itemp(i)=ibase(i-1,ja)+ipc(i)*ibase(ndeg,ja)
180 continue
do 190 i=1,ndeg
ibase(i,npow+ja)=mod(itemp(i),np)
190 continue
170 continue
c we now generate a table of inverses to help us do arithmetic in GF(np)
do 200 j=1,np-1
do 210 i=1,np-1
if(mod(i*j,np).ne.1)go to 210
irep(j)=i
go to 200
210 continue
stop "error 210"
200 continue
c put basis in a normal form.
do 220 j=1,2*npow
c find first non-zero in column j
do 230 i=1,ndeg
if(ibase(i,j).ne.0)go to 240
230 continue
stop "error 230"
c record position of first non-zero
240 ipiv(j)=i
c multiply column so non-zero becomes 1
imult=irep(ibase(i,j))
do 250 i=1,ndeg
ibase(i,j)=mod(ibase(i,j)*imult,np)
250 continue
c zero remaining elements in row
do 260 ja=1,2*npow
if(ja.eq.j)go to 260
imult=ibase(ipiv(j),ja)
do 270 i=1,ndeg
ibase(i,ja)=mod(ibase(i,ja)-imult*ibase(i,j),np)
if(ibase(i,ja).lt.0)ibase(i,ja)=ibase(i,ja)+np
270 continue
260 continue
220 continue
c now construct perpendicular basis
jp=0
do 280 j=1,ndeg
c look for row not among the 2*npow recorded in ipiv
do 290 i=1,2*npow
if(ipiv(i).eq.j)go to 280
290 continue
jp=jp+1
c zero jp'th vector in perpendicular basis
do 300 i=1,ndeg
iperp(i,jp)=0
300 continue
c fill in elements in ipiv rows so as to make inner products 0
do 310 ja=1,2*npow
iperp(ipiv(ja),jp)=ibase(j,ja)
310 continue
c note -1 = np - 1 mod np
iperp(j,jp)=np-1
280 continue
c construct perfect difference set mod n**2+n+1
c look for powers of x in space spanned by GF(n), x
c put 0 in set
ids(1)=0
nc=1
c initialize iit
do 320 j=1,ndeg
iit(j)=0
320 continue
iit(1)=1
c look for powers of x in space spanned by GF(n), x
do 330 j=1,n*n+n
c multiply by x
itemp(1)=ipc(1)*iit(ndeg)
do 340 i=2,ndeg
itemp(i)=iit(i-1)+ipc(i)*iit(ndeg)
340 continue
do 350 i=1,ndeg
iit(i)=mod(itemp(i),np)
350 continue
c check inner products
do 360 ja=1,npow
iip=0
do 370 i=1,ndeg
iip=iip+iperp(i,ja)*iit(i)
370 continue
iip=mod(iip,np)
if(iip.ne.0)go to 330
360 continue
nc=nc+1
ids(nc)=j
330 continue
c check that difference set is right size
if(nc.ne.n+1)stop "error 330"
c output difference set
c write(6,1000)n,(ids(j),j=1,n+1)
c1000 format(1x,i5,5x,(10i5))
c check for better rulers
c cycle over multipliers, don't need to try j and -j mod (n*n+n+1)
c do 420 j=1,n*n+n
do 420 j=1,(n*n+n+1)/2
c check if multiplier prime to modulus
if(igcd(j,n*n+n+1).ne.1)go to 420
c multiply difference set
do 430 i=1,n+1
mw(i)=mod(ids(i)*j,n*n+n+1)
430 continue
c sort new difference set
array_len = n + 1
array_size = 4
CALL qsort(mw,array_len, array_size,cmp_function)
c unwrap difference set
do 440 i=1,n+1
mw(i+n+1)=mw(i)+n*n+n+1
440 continue
c check for new records
do 450 ia=1,n+1
do 460 ib=1,n
if(mw(ia+ib)-mw(ia).ge.len(ib+1))go to 460
c new record ruler
len(ib+1)=mw(ia+ib)-mw(ia)
nval(ib+1)=n
do 470 ja=1,ib+1
mrec(ja,ib+1)=mw(ia+ja-1)-mw(ia)
470 continue
460 continue
450 continue
420 continue
10 continue
c output maximum rulers
do 500 j=2,maxn
if(nval(j).eq.0)go to 500
c put ruler in standard form (flip if needed)
if(mrec((j+1)/2,j)+mrec((j+2)/2,j).lt.len(j))go to 520
c flip ruler
do 510 i=1,(j+1)/2
mtemp=mrec(i,j)
mrec(i,j)=len(j)-mrec(j+1-i,j)
mrec(j+1-i,j)=len(j)-mtemp
510 continue
520 continue
c
c write results for j marks
c
c j,length and prime power to unit 6 (terminal)
c j,length and prime power to unit 1 (disk)
c ruler to unit 1 (disk)
c
write(6,1010)j,len(j),nval(j)
write(1,1020)j,len(j),nval(j)
write(1,1030)(mrec(i,j),i=1,j)
1010 format(1x,3i10)
1020 format(3i10)
1030 format(10i6)
500 continue
c mark end of disk file
write(1,1020)0,0,0
stop
end
c generate random vector of n integers 0,...,np-1
subroutine irand(l,np,n,x,iseed)
integer*4 l(*)
real*8 x(*)
real*8 dseed/1.d0/
save dseed
c generate random 0-1 real*8 vector
CALL DLARNV( 1, ISEED, N, X )
c convert to integer 0,...,np-1
do 10 j=1,n
l(j)=np*x(j)
10 continue
return
end
c find gcd of ia,ib using Euler's method
function igcd(ia,ib)
ja=ia
jb=ib
1 jc=mod(ja,jb)
ja=jb
jb=jc
if(jb.ne.0)go to 1
igcd=ja
return
end
integer(4) function cmp_function(a1, a2)
integer(4) a1, a2
cmp_function=a1-a2
end function