--- /dev/null
+c===========================================================================
+c
+c This file is part of TISEAN
+c
+c Copyright (c) 1998-2007 Rainer Hegger, Holger Kantz, Thomas Schreiber
+c
+c TISEAN is free software; you can redistribute it and/or modify
+c it under the terms of the GNU General Public License as published by
+c the Free Software Foundation; either version 2 of the License, or
+c (at your option) any later version.
+c
+c TISEAN is distributed in the hope that it will be useful,
+c but WITHOUT ANY WARRANTY; without even the implied warranty of
+c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+c GNU General Public License for more details.
+c
+c You should have received a copy of the GNU General Public License
+c along with TISEAN; if not, write to the Free Software
+c Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+c
+c===========================================================================
+c clustering a dissimilarity matrix
+c see Schreiber and Schmitz, Phys. Rev. Lett. 79 (1997) 1475
+c author T. Schreiber (1998)
+c===========================================================================
+
+ parameter(npmax=1000)
+ dimension d(npmax,npmax), iu(npmax), ifix(npmax)
+ character*72 file, fout, filex
+ data iverb/3/
+
+ call whatido("clustering a dissimilarity matrix",iverb)
+ ncl=imust("#")
+ iflag=lopt("=",1)
+ call stcan('X',filex,' ')
+ isout=igetout(fout,iverb)
+
+ call nthstring(1,file)
+ call infile(file,iunit,iverb)
+ if(file.eq."-") file="stdin"
+ if(isout.eq.1) call addsuff(fout,file,"_clust")
+ do 10 i=1,npmax
+ do 10 j=1,npmax
+ 10 d(i,j)=-1e20
+ np=0
+ 1 read(iunit,*,end=999) i,j,dij
+ d(i,j)=dij
+ np=max(i,j,np)
+ goto 1
+ 999 if(iv_io(iverb).eq.1) write(0,'(a,i)') "matrix size ", np
+ dmean=0
+ nd=0
+ do 20 i=1,np
+ do 20 j=1,np
+ if(d(i,j).ne.-1e20) then
+ nd=nd+1
+ dmean=dmean+d(i,j)
+ endif
+ 20 continue
+ do 30 i=1,np
+ do 30 j=1,np
+ 30 if(d(i,j).eq.-1e20) d(i,j)=dmean/nd
+ do 40 i=1,np
+ 40 ifix(i)=0
+ if(filex.ne." ") then
+ open(10,file=filex,status='old',err=998)
+ nfix=0
+ 2 read(10,*,end=998,err=2) i, iff
+ if(i.lt.1.or.i.gt.np.or.iff.gt.ncl.or.iff.lt.1) goto 1
+ ifix(i)=iff
+ nfix=nfix+1
+ endif
+ 998 if(nfix.eq.np) stop "all fixed."
+ call clustering(np,d,npmax,ncl,nfix,ifix,iu,iverb,iflag)
+ call outfile(fout,iunit,iverb)
+ do 50 n=1,np
+ 50 write(iunit,*) iu(n), (costi(np,iu,d,n,ic,iflag),ic=1,ncl)
+ end
+
+ subroutine usage()
+c usage message
+
+ call whatineed("-## [-= -X xfile] file")
+ call popt("#","number of clusters")
+ call popt("=","if set, bias towards similar size clusters")
+ call popt("X","list of indices with fixed cluster assignments")
+ call pout("file_clust")
+ call pall()
+ call ptext("Verbosity levels (add what you want):")
+ call ptext(" 1 = input/output" )
+ call ptext(" 2 = state of clustering")
+ call ptext(" 8 = temperature / cost at cooling")
+ stop
+ end
+
+ subroutine clustering(np,d,npmax,ncl,nfix,ifix,iu,iverb,iflag)
+ parameter(nt0=20,tfac=10.,tstep=0.99,ntotmaxf=20,nsuccmaxf=2)
+ external rand
+ character*1 c
+ dimension d(npmax,npmax), iu(*), ifix(*)
+ equivalence (c,ic)
+ data c/'A'/
+
+ ntotmax=(np-nfix)*ntotmaxf
+ nsuccmax=(np-nfix)*nsuccmaxf
+ se=0.
+ se2=0.
+ do 10 nt=1,nt0
+ call ranconf(np,iu,ncl,ifix)
+ e=cost(np,iu,d,ncl,iflag)
+ se=se+e
+ 10 se2=se2+e**2
+ t=tfac*sqrt(se2/nt0-(se/nt0)**2)
+
+ ntot=0
+ nsucc=0
+ 1 call cconf(np,iu,ncl,nch,iuold,ifix)
+ ec=cost(np,iu,d,ncl,iflag)
+ ntot=ntot+1
+ if(ec.lt.e.or.(rand(0.0).lt.exp(-(ec-e)/t))) then
+ e=ec
+ nsucc=nsucc+1
+ else
+ iu(nch)=iuold
+ endif
+ if(ntot.eq.ntotmax .or. nsucc.eq.nsuccmax) then
+ if(nsucc.eq.0) return
+ ntot=0
+ nsucc=0
+ if(iv_clust(iverb).eq.1) write(istderr(),'(80a1)')
+ . (ic+iu(n)-1,n=1,np)
+ if(iv_cool(iverb).eq.1) write(istderr(),*) t, e
+ t=t*tstep
+ endif
+ goto 1
+ end
+
+ function cost(np,iu,d,ncl,iflag)
+ parameter(npmax=1000)
+ dimension d(npmax,npmax), iu(*), ictab(npmax)
+
+ cost=0
+ do 10 ic=1,ncl
+ nic=0
+ do 20 n=1,np
+ if(iu(n).ne.ic) goto 20
+ nic=nic+1
+ ictab(nic)=n
+ 20 continue
+ cc=0
+ do 30 ii=1,nic
+ i=ictab(ii)
+ do 30 jj=1,nic
+ j=ictab(jj)
+ 30 cc=cc+d(i,j)
+ 10 if(nic.gt.0) cost=cost+cc/(1+(1-iflag)*(nic-1))
+ end
+
+ function costi(np,iu,d,nn,ic,iflag)
+ parameter(npmax=1000)
+ dimension d(npmax,npmax), iu(*), ictab(npmax)
+
+ costi=0
+ nic=0
+ do 20 n=1,np
+ if(iu(n).ne.ic) goto 20
+ nic=nic+1
+ ictab(nic)=n
+ 20 continue
+ cc=0
+ do 30 jj=1,nic
+ j=ictab(jj)
+ 30 cc=cc+d(nn,j)+d(j,nn)
+ if(nic.gt.0) costi=0.5*cc/(1+(1-iflag)*(nic-1))
+ end
+
+ subroutine ranconf(np,iu,ncl,ifix)
+ external rand
+ dimension iu(*), ifix(*)
+
+ do 10 n=1,np
+ iu(n)=ifix(n)
+ 10 if(ifix(n).eq.0) iu(n)=min(int(rand(0.0)*ncl)+1,ncl)
+ end
+
+ subroutine cconf(np,iu,ncl,nch,iuold,ifix)
+ external rand
+ dimension iu(*), ifix(*)
+
+ 1 nch=min(int(rand(0.0)*np)+1,np)
+ if(ifix(nch).ne.0) goto 1
+ iuold=iu(nch)
+ iu(nch)=iuold+int(rand(0.0)*(ncl-1))+1
+ if(iu(nch).gt.ncl) iu(nch)=iu(nch)-ncl
+ end